我有一个整数列表/数组,如果子数组先升后降,则将其称为 peak 。例如:
bcryptjs
包含
[5,5,4,5,4]
这是一个高峰。
也考虑
[4,5,4]
包含
[6,5,4,4,4,4,4,5,6,7,7,7,7,7,6]
这是一个高峰。
给出一个输入列表,我想找到其中包含的所有最小长度的峰并报告它们。在上面的示例中,[6,7,7,7,7,7,6]
也是一个峰值,但是我们删除了第一个元素,它仍然是一个峰值,因此我们不进行报告。
所以对于输入列表:
[5,6,7,7,7,7,7,6]
我们会回来
L = [5,5,5,5,4,5,4,5,6,7,8,8,8,8,8,9,9,8]
我在为此设计一个不错的算法时遇到了问题。任何帮助将不胜感激。
答案 0 :(得分:4)
itertools
这是使用itertools.groupby
检测峰的简短解决方案。然后将识别峰的组解压缩以产生实际序列。
from itertools import groupby, islice
l = [1, 2, 1, 2, 2, 0, 0]
fst, mid, nxt = groupby(l), islice(groupby(l), 1, None), islice(groupby(l), 2, None)
peaks = [[f[0], *m[1], n[0]] for f, m, n in zip(fst, mid, nxt) if f[0] < m[0] > n[0]]
print(peaks)
[[1, 2, 1], [1, 2, 2, 0]]
上面的解决方案很优雅,但是由于创建了groupby
的三个实例,所以该列表被遍历了三遍。
这是使用单个遍历的解决方案。
def peaks(lst):
first = 0
last = 1
while last < len(lst) - 1:
if lst[first] < lst[last] == lst[last+1]:
last += 1
elif lst[first] < lst[last] > lst[last+1]:
yield lst[first:last+2]
first = last + 1
last += 2
else:
first = last
last += 1
l = [1, 2, 1, 2, 2, 0, 0]
print(list(peaks(l)))
[[1, 2, 1], [1, 2, 2, 0]]
在使用timeit
进行基准测试时,我注意到使用循环的解决方案的性能提高了约20%。对于简短列表,groupby
的开销可能会使该数字增加40%。基准测试是在Python 3.6上完成的。