每个由(至少)k个元素

时间:2016-08-27 03:18:26

标签: python algorithm dynamic-programming

给出一个数字列表,找出时间复杂度为o(n)且空间复杂度为o(1)的非相邻元素的最大总和,我可以使用:

sum1= 0
sum2= list[0]

for i in range(1, len(list)):
    num= sum1
    sum1= sum2+ list[i]
    sum2= max(num, sum2)

print(max(sum2, sum1))

这个代码只有在k = 1 [求和数之间只有一个元素]时才能工作,如何通过动态编程改变k值来改善它。其中k是求和数之间的元素数。 例如:

list = [5,6,4,1,2] k = 1 答案= 11#5 + 4 + 2

list = [5,6,4,1,2] k = 2 答案= 8#6 + 2

list = [5,3,4,10,2] k = 1 答案= 15#5 + 10

4 个答案:

答案 0 :(得分:4)

可以通过空间 O(k)和时间 O(nk)来解决这个问题。如果 k 是常量,则符合您问题中的要求。

算法从位置 k + 1 循环到 n 。 (如果数组比那个短,显然可以在 O(k)中解决。在每一步,它都维护一个长度为 k + 1 的数组best,这样best j 条目就是找到的最佳解决方案到目前为止,它使用的最后一个元素至少是当前位置左侧的 j

初始化best是通过为其条目 j 设置数组中位置 1,...,k + 1 - 中最大的非负条目来完成的。 Ĵ。因此,例如,best[1]是位置 1,...,k 中最大的非负数条目,而best[k + 1]为0。

当在数组的位置 i 时,使用元素 i 。如果使用,相关best到现在为best[1],请写u = max(best[1] + a[i], best[1])。如果未使用元素 i ,那么每个"至少"部分移位一个,因此对于 j = 2,...,k + 1 best[j] = max(best[j], best[j - 1])。最后,设置best[1] = u

在算法终止时,解决方案是best中的最大项目。

答案 1 :(得分:2)

编辑: 我误解了这个问题,如果你需要在其间有“至少”k个元素,那么下面是O(n^2)解决方案。

如果数字为非负数,则DP递归关系为:

DP[i] = max (DP[j] + A[i]) For all j st 0 <= j < i - k 
      = A[i] otherwise.

如果数组中也有负数,那么我们可以使用Kadane算法的想法:

DP[i] = max (DP[j] + A[i]) For all j st 0 <= j < i - k && DP[j] + A[i] > 0
      = max(0,A[i]) otherwise.

答案 2 :(得分:1)

这是Ami Tavory描述的算法的快速实现(据我所知)。它适用于任何序列,但如果您的列表全部为负数,则最大总和将为0(空子序列的总和)。

import collections

def max_sum_separated_by_k(iterable, k):
    best = collections.deque([0]*(k+1), k+1)
    for item in iterable:
        best.appendleft(max(item + best[-1], best[0]))
    return best[0]

这使用O(k)空格和O(N)时间。所有deque操作,包括向一端附加值(并从另一端隐式删除一个以保持长度限制)和从末尾读取,都是O(1)

如果您希望算法返回最大子序列(而不仅仅是其总和),您可以将deque的初始化更改为以空列表而不是0开头,然后追加{ {1}}在循环体中。但这样效率会相当低,因为它会在整个地方添加max([item] + best[-1], best[0], key=sum)个操作。

答案 3 :(得分:0)

不确定复杂程度,但编码效率让我感到满意

max([sum(l[i::j]) for j in range(k,len(l)) for i in range(len(l))])

(我已list替换l变量,而不是踩到关键字。