找到最大的连续和,使得它的最小值和它的补码最大

时间:2014-03-04 20:16:02

标签: algorithm

我给了一系列数字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-1tab[i]+=tab[i-j]。因此tab[j]是从开头到j的总和。

我检查所有可能的总和a_i+...+a_j=tab[j]-tab[i-1]并从总和中减去它,取最小值并查看它是否比以前更大。

需要O(n^2)。这让我非常伤心和悲惨。还有更好的方法吗?

2 个答案:

答案 0 :(得分:4)

似乎可以在O(n)时间内完成。

  1. 计算总和S。理想的子序列和是最接近S/2的最长的一个。
  2. i=j=0开始,增加j,直到sum(a_i..a_j)sum(a_i..a_{j+1})尽可能接近S / 2。请注意哪个更接近并保存i_best,j_best,sum_best
  3. 的值
  4. 再次增加i,然后再次增加j,直到sum(a_i..a_j)sum(a_i..a_{j+1})尽可能接近S / 2。注意哪些更接近并且如果它们更好则替换i_best,j_best,sum_best的值。重复此步骤直到完成。
  5. 请注意,ij都不会递减,因此它们总共最多可以更改O(n)次。由于所有其他操作仅占用恒定时间,因此会导致整个算法的运行时间为O(n)。

答案 1 :(得分:1)

让我们先做一些澄清。

  1. 序列的subsequence实际上是序列索引的子集。 Haivng说,特别是在你的序列中有不同元素的情况下,你的问题将减少到着名的Partition问题,这个问题已知是NP完全的。如果是这种情况,您可以设法解决O(Sn)中的问题,其中“n”是元素的数量,“S”是总和。这不是多项式时间,因为“S”可以任意大。
  2. 因此,让我们考虑具有连续子序列的情况。您需要两次观察数组元素。首先将它们总结为一些“S”。在第二轮中,您仔细调整阵列长度。让我们假设您知道a [i] + a [i + 1] + ... + a [j]> S / 2.然后你让i = i + 1来减少总和。相反,如果它更小,你会增加j。
  3. 此代码以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])