代码之家  ›  专栏  ›  技术社区  ›  Soumyaroop Roy

使用itertools计算后缀最大值。积累

  •  3
  • Soumyaroop Roy  · 技术社区  · 7 年前

    计算整数序列后缀最大值的推荐方法是什么?

    以下是暴力方法( O(n**2) 时间),根据问题定义:

    >>> A
    [9, 9, 4, 3, 6]
    >>> [max(A[i:]) for i in range(len(A))]
    [9, 9, 6, 6, 6]
    

    O(n) 方法使用 itertools.accumulate() 如下所示,它使用两个列表构造函数:

    >>> A
    [9, 9, 4, 3, 6]
    >>> list(reversed(list(itertools.accumulate(reversed(A), max))))
    [9, 9, 6, 6, 6]
    

    有没有一种更像蟒蛇的方式来做到这一点?

    2 回复  |  直到 6 年前
        1
  •  3
  •   user2357112    7 年前

    切片反转使内容更简洁,嵌套更少:

    list(itertools.accumulate(A[::-1], max))[::-1]
    

    尽管如此,您仍然希望将其捆绑到函数中:

    from itertools import accumulate
    
    def suffix_maximums(l):
        return list(accumulate(l[::-1], max))[::-1]
    

    如果你用的是NumPy numpy.maximum.accumulate :

    import numpy
    
    def numpy_suffix_maximums(array):
        return numpy.maximum.accumulate(array[::-1])[::-1]
    
        2
  •  1
  •   Nathan Vērzemnieks    7 年前

    就我个人而言,当我想到“Pythonic”时,我会想到“简单易读”,所以这里是我的Pythonic版本:

    def suffix_max(a_list):
        last_max = a[-1]
        maxes = []
        for n in reversed(a):
            last_max = max(n, last_max)
            maxes.append(last_max)
        return list(reversed(maxes))
    

    值得一提的是,这看起来比 itertools.accumulate 方法,但对于100000个整数的列表,我们讨论的是25ms与17ms,所以这可能没什么关系。

    如果最关心的是速度,并且您希望看到的数字范围明显小于您正在处理的列表的长度,那么它可能值得使用 RLE :

    def suffix_max_rle(a_list):
        last_max = a_list[-1]
        count = 1
        max_counts = []
        for n in a_list[-2::-1]:
            if n <= last_max:
                count += 1
            else:
                max_counts.append([last_max, count])
                last_max = n
                count = 1
        if n <= last_max:
            max_counts.append([last_max, count])
        return list(reversed(max_counts))
    

    对于范围为0-10000的100000 Int列表,这大约是上述方法的4倍,大约是itertools方法的2.5倍。同样,如果您的数字范围明显小于列表的长度,那么它也会占用更少的内存。