我给了一系列数字a_1,a_2,...,a_n
。它的总和是S=a_1+a_2+...+a_n
,我需要找到一个子序列a_i,...,a_j
,这样min(S-(a_i+...+a_j),a_i+...+a_j)
是最大的(两个总和必须是非空的)。
示例:
1,2,3,4,5
序列为3,4
,因为min(S-(a_i+...+a_j),a_i+...+a_j)=min(8,7)=7
(并且它是可能检查其他子序列的最大可能值)。
我试图以这种方式做到这一点。
我将所有值加载到数组tab[n]
。
我这样做n-1
次tab[i]+=tab[i-j]
。因此tab[j]
是从开头到j
的总和。
我检查所有可能的总和a_i+...+a_j=tab[j]-tab[i-1]
并从总和中减去它,取最小值并查看它是否比以前更大。
需要O(n^2)
。这让我非常伤心和悲惨。还有更好的方法吗?
答案 0 :(得分:4)
似乎可以在O(n)时间内完成。
S
。理想的子序列和是最接近S/2
的最长的一个。i=j=0
开始,增加j
,直到sum(a_i..a_j)
和sum(a_i..a_{j+1})
尽可能接近S / 2。请注意哪个更接近并保存i_best,j_best,sum_best
。i
,然后再次增加j
,直到sum(a_i..a_j)
和sum(a_i..a_{j+1})
尽可能接近S / 2。注意哪些更接近并且如果它们更好则替换i_best,j_best,sum_best
的值。重复此步骤直到完成。请注意,i
和j
都不会递减,因此它们总共最多可以更改O(n)次。由于所有其他操作仅占用恒定时间,因此会导致整个算法的运行时间为O(n)。
答案 1 :(得分:1)
让我们先做一些澄清。
此代码以O(n)运行。
Python代码:
from math import fabs
a = [1, 2, 3, 4, 5]
i = 0
j = 0
S = sum(a)
s = 0
while s + a[j] <= S / 2:
s = s + a[j]
j = j + 1
s = s + a[j]
best_case = (i, j)
best_difference = fabs(S / 2 - s)
while True:
if fabs(S / 2 - s) < best_difference:
best_case = (i, j)
best_difference = fabs(S / 2 - s)
if s > S / 2:
s -= a[i]
i += 1
else:
j += 1
if j == len(a):
break
s += a[j]
print best_case
i = best_case[0]
j = best_case[1]
print "Best subarray = ", a[i:j + 1]
print "Best sum = " , sum(a[i:j + 1])