【问题标题】:compute suffix maximums using itertools.accumulate使用 itertools.accumulate 计算后缀最大值
【发布时间】:2018-07-31 10:10:40
【问题描述】:

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

以下是蛮力方法 (O(n**2)time),基于问题定义:

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

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

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

有没有更 Pythonic 的方式来做到这一点?

【问题讨论】:

  • 如果您将max 应用于越来越多的数字,我认为这不是O(n)
  • 它没有 - 它只是重复最多两个数字。一些快速测试证实了O(n) 的估计。
  • @ReutSharabani 是的,itertools.accumulate 的工作方式与 reduce 类似,因为它需要一个二元运算符,但它不是将 reducing 变为单个数字,而是累积所有中间结果。无论如何,我认为您的itertools.accumualte 解决方案非常pythonic。但即使是等效的 for 循环也可以。
  • @juanpa.arrivillaga 知道了

标签: python python-3.x algorithm data-structures itertools


【解决方案1】:

切片反转使事情更简洁,嵌套更少:

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】:

当我个人认为“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 方法慢了大约 50%,但对于 100,000 个整数的列表,我们说的是 25 毫秒与 17 毫秒,所以这可能没什么大不了的。

如果速度是最重要的问题,并且您希望看到的数字范围明显小于您正在处理的列表长度,那么可能值得使用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 范围内的 100,000 个整数的列表,这比上面的方法快 4 倍,比 itertools 方法快约 2.5 倍。同样,如果您的数字范围明显小于列表的长度,那么它也将占用更少的内存。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-29
    • 1970-01-01
    相关资源
    最近更新 更多