简体   繁体   English

如何在python的列表算法中减少k个连续数字的最大和的执行时间

[英]How to decrease execution time of maximum sum of k consecutive numbers in a list algorithm in python

my problem is to find the maximum sum of k consecutive numbers in a given list. 我的问题是在给定列表中找到k个连续数字的最大和。 for instance: l = [2,3,5,1,6] then for k =2 the result would be 8(3+5). 例如:l = [2,3,5,1,6],那么对于k = 2,结果将是8(3 + 5)。 I know a good algorithm would be to first find the sum of the first k numbers then add the next element to the sum and subtract the first element of the k numbers: 我知道一个好的算法是先找到前k个数字的和,然后将下一个元素加到和,然后减去k个数字的第一个元素:

2+3 => 5
5-2+5 => 8
... 

I came up with this: 我想出了这个:

def f(l, k):
    M= 0
    temp = sum(l[0:k])
    for i in range(1,k):
        temp += a[l+1]-l[i-1]
        if temp > M:
            M = temp
    return M

but unfortunately it only works with k = 2? 但不幸的是,它仅适用于k = 2? so I have two issues: 所以我有两个问题:

  1. Why my code doesn't work with higher k's?(what is the bug and how can I fix it?) 为什么我的代码不能与较高的k一起使用?(什么是错误,我该如何解决?)
  2. Is there any better way(time wise) to solve the main problem?will this algorithm work quick enough if for example len(l) = 100000 and k = 2000?how can I determine its execution time only by looking at the code? 有什么更好的方法(在时间上明智)来解决主要问题?例如,如果len(l)= 100000且k = 2000,该算法能否足够快地工作?如何仅通过查看代码来确定其执行时间?

The idea you described is correct, but your implementation is wrong. 您描述的想法是正确的,但是您的实现是错误的。

  1. Your variable M is equivalent to cumax below. 您的变量M等于下面的cumax It should be initialized to the sum of the first k items, not 0. 应该将其初始化为前k个项的总和,而不是0。
  2. Your range of the start of the k numbers to consider should be N - k + 1 , the largest position in the sequence for a window of size k. 您要考虑的k数字的起始范围应为N - k + 1 ,即大小为k的窗口序列中的最大位置。
  3. Your temp is equivalent to cusum . 你的temp相当于cusum The line temp += a[l+1]-l[i-1] is wrong. 线temp += a[l+1]-l[i-1]是错误的。 I don't know where you get a from. 我不知道你从哪里得到a I think you meant temp += l[i + k] - l[i - 1] . 我认为您的意思是temp += l[i + k] - l[i - 1]

     def f(l, k): assert len(l) >= k # Start of max sum of k consecutive number start_idx = 0 # Current max sum of k consecutive number cumax = cusum = sum(l[:k]) # Slide a window of size k from second element onwards N = len(l) for i in range(1, N - k + 1): # Subtract element before start of window and add rightmost element cusum = cusum + l[i + k - 1] - l[i - 1] # Update start of and latest max sum of k consecutive number if # necessary if cusum > cumax: cumax = cusum start_idx = i return start_idx, cumax 

The time complexity is O(N) and memory complexity is O(1). 时间复杂度为O(N),内存复杂度为O(1)。 In reality, for long sequences, the approach by @dobkind using convolution would probably be fastest. 实际上,对于长序列,@ dobkind使用卷积的方法可能最快。

def f_convolve(l, k):
    start_idx = np.argmax(np.convolve(l, np.ones(k,), 'valid'))
    return start_idx, np.sum(l[start_idx : start_idx + k])

If you have memory to spare and l is not too large, this implementation works even better than the previous two 如果您有剩余的内存并且l不太大,则此实现的效果甚至比前两个更好

def f_numpy_cusum(l, k):
    cumsums = np.cumsum(l)
    cumsums[k :] -= cumsums[: len(cumsums) - k ]
    cumsums = cumsums[ k- 1:]
    start = np.argmax(cumsums)
    return start, np.sum(l[start : start + k])

The time runs for the above 3 functions with len(l) = 100000 and k = 2000 are 以上三个函数的时间运行,其中len(l) = 100000和k = 2000

f 32.6 ms +- 78.5 us per loop (mean +- std. dev. of 7 runs, 10 loops each) f 32.6毫秒+-每个循环78.5 us(平均值+-标准开发7次运行,每个循环10个)

f_convolve 26.3 ms +- 183 us per loop (mean +- std. dev. of 7 runs, 10 loops each) f_convolve每个循环26.3毫秒+ f_convolve us(平均值+-标准开发的7次运行,每个循环10次)

f_numpy_cusum 718 us +- 3.81 us per loop (mean +- std. dev. of 7 runs, 1000 loops each) f_numpy_cusum每循环718 us + f_numpy_cusum us(平均值+-标准开发7次运行,每个循环1000次)

We should use dynamic programming for this purpose and do this in O(n) complexity 为此,我们应该使用动态编程,并且要以O(n)复杂度进行操作

from random import randint

test=[randint(1,10) for i in range(5)]
# find cumulative sum use np.cumsum or write is yourself
print(test)
cumsum=[0]*(len(test)+1)
cumsum[1]=test[0]
for i in range(2,len(test)+1):
    cumsum[i]=cumsum[i-1]+test[i-1]
print(cumsum)
#define k
k=3
# m denotes the maximum element
m=0
for i in range(len(test)-k+1):
   m=max(m,cumsum[k+i]-cumsum[i])
   print(cumsum[k+i]-cumsum[i])
# the answer is printed 
print(m)

INPUT 输入

[10, 5, 1, 1, 7]
k=3

OUTPUT 输出值

16

You can use numpy.convolve as follows: 您可以按如下方式使用numpy.convolve

k = 2     
max_sum = np.max(np.convolve([2,3,5,1,6], np.ones(k,), 'same'))

With k=2000 and len(l)=100000 this code is running in 0.04 sec on my i7 machine: k=2000len(l)=100000此代码在我的i7机器上以0.04秒的速度运行:

from random import randint
import time

def test_max_sum(k, len_l):
    num_trials = 100
    total = 0
    test = [randint(1, 10) for i in range(len_l)]
    for i in range(num_trials):
        start = time.clock()
        max_sum = np.max(np.convolve(test, np.ones(k, ), 'same'))
        end = time.clock()
        total += end - start
    total /= num_trials
    print total

This is really not my expertise, but wouldnt zipping together the lists be quite effective? 这真的不是我的专长,但是将列表压缩在一起会不会很有效?

Something in the lines of: 符合以下条件的东西:

from itertools import islice

l = [2,3,5,1,6]

def max_consecutive(ar, k=2):
    combos = zip(*(islice(ar,i,None) for i in range(k)))
    return max(map(sum, combos))

print(max_consecutive(l)) 
print(max_consecutive(l, k=3))

Returns 8 and 12 返回812

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM