如何在python

时间:2018-10-17 07:13:29

标签: python algorithm

我的问题是在给定列表中找到k个连续数字的最大和。 例如: l = [2,3,5,1,6],则对于k = 2,结果将是8(3 + 5)。 我知道一个好的算法是先找到前k个数字的和,然后将下一个元素加到和,然后减去k个数字的第一个元素:

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

我想到了这个

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

但是不幸的是,它仅适用于k = 2? 所以我有两个问题:

  1. 为什么我的代码不能与更高的k一起使用?(什么是错误,我该如何解决?)
  2. 是否有更好的方法(在时间上)来解决主要问题?例如,如果len(l)= 100000且k = 2000,该算法能否足够快地工作?如何仅通过查看码?

4 个答案:

答案 0 :(得分:4)

您描述的想法是正确的,但是您的实现是错误的。

  1. 您的变量M等效于下面的cumax。它应该是 初始化为前k个项的总和,而不是0。
  2. 要考虑的k数字开头的范围应为N - k + 1,即大小为k的窗口序列中的最大位置。
  3. 您的temp等同于cusumtemp += a[l+1]-l[i-1]行是错误的。我不知道您从哪里得到a。一世 以为你的意思是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
    

时间复杂度为O(N),内存复杂度为O(1)。实际上,对于长序列,@ 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])

如果您有剩余的内存并且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])

上述3个函数的运行时间为len(l) = 100000和k = 2000 are

f 每个循环32.6毫秒+-78.5 us(平均开发标准-运行7次,每个循环10个循环)

f_convolve 26.3 ms +-每个循环183 us(平均+-标准开发,运行7次,每个循环10个)

f_numpy_cusum 每个循环718 us +-3.81 us(平均值+-标准开发的7次运行,每个循环1000次)

答案 1 :(得分:2)

为此,我们应该使用动态编程,并以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)

输入

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

输出

16

答案 2 :(得分:2)

您可以按以下方式使用numpy.convolve

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

使用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

答案 3 :(得分:1)

这真的不是我的专长,但是将列表压缩在一起会不会很有效?

以下内容:

export type KeysOfType<T, TProp> = { [P in keyof T]: T[P] extends TProp ? P : never }[keyof T];

class A {
    public prop1: number;
    public prop2: string;
    public prop3: string;
}
class B<O extends Record<K, string> & A, K extends string | number | symbol = KeysOfType<O, string> >
{
    constructor() {

    }
    private prop: K;
    private prop2: keyof A

    public method(): void {
        let o!: O;
        let notTypedAsString = o[this.prop]; // if you hover over it it will be O[K] 
        notTypedAsString.bold();//but it behaves as string
        o.prop1 // number, A memebrs that arae not strings still work as expected
    }
}

new B<A>()
class A2 extends A {        
    public prop4: number;
    public prop5: string;
}
new B<A2>()

返回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)) 8