找到最长的非负子数组

时间:2014-02-11 21:49:16

标签: performance algorithm arrays

我正在寻找一种更有效的替代蛮力来寻找具有非负和的数组的最长子数组。该数组中的数字范围为-5到5。

例如,如果您有一个数组A

4 2 -5 3 0 -2 -2 -3 4 -4 -3 -2 1

那么最长的非负子数组是

4 2 -5 3 0 -2 -2 -3 4,长度为9

我正在考虑的解决方案是保持最佳解决方案和最佳后缀,其中最佳后缀始终以最后检查点A[i]结束。如果最佳后缀比最佳解决方案更长,我们会将最佳解决方案更新为最佳后缀。

后缀将由夹在两个正子阵列之间的负子阵列组成。 所以,在这种情况下从左到右:

4 2是第一个正子阵列 -5是负子阵列 3 0 -2是第二个正子阵列

然后程序检查两个正子阵列的总和是否大于负子阵列。如果是这样,整个最佳后缀成为新的第一个正子数组。如果没有,则转储第一个正负子数组,第二个正子数组转为第一个子数组,依此类推。

理论上,程序应该能够在线性时间内逐步检查最佳解决方案。

但这个答案似乎不正确。

所以我正在寻找一个更好的解决方案,或至少提示一个更好的方向

任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:3)

这被称为“最长的偏差间隔”,是生物学中的常见问题。这是算法(在您的情况下L==0):

Input: A nonempty array of n real numbers `A[1 . . . n]` and a lower bound `L`.

Output: The start and end index of the longest segment of `A` with sum at least `L`.

C[0 . . . n] and M[0 . . . n] are arrays of size n +1, as defined in the context.

M[0]←C[0]←0; x←y←0;
for i←1 to n do
    C[i]←C[i −1] + A[i];
    if C[i −1]<C[M[i −1]] then M[i]←i −1 else M[i] = M[i −1];
    k←i −y +x − 1;
    while k >0 do
        if C[i] − C[M[k]] >= L then k←M[k] else break;
        x←k +1; y←i;
    end while
    OUTPUT A(x, y);
end for

见Chen,Kuan-Yu和Chao-Mao Chao。 “用于定位满足总和或平均约束的最长和最短段的最佳算法。”信息处理信函96.6(2005):197-201。

以下是概念的说明:

enter image description here

答案 1 :(得分:1)

HINTS

您可以通过以下方式在线性时间内完成此操作:

  1. 首先计算阵列A的累积总和
  2. 然后计算一个数组B,在索引i右侧的A中给出最大值
  3. 计算一个数组C,给出索引i左侧A中的最小值
  4. B和C都是非增加数组。

    然后,对于阵列C中的每个起始位置,计算阵列B中的最大结束位置,使得B [end]> C [start]。这可以通过以下方式在线性时间内完成:

    1. 以start = 0开始
    2. 增加结束直到B [end + 1]&lt; = C [start]
    3. 递增开始并返回步骤2
    4. end-start的最大值对应于最长的子阵列。

      说明

      主要思想是,一旦你有一个数组的累积和,你可以通过减法计算一个子阵列的值。

      例如,数组:

      4 2 -5 3 0 -2 
      

      有累积值:

      A = [4 6 1 4 4 2]
      

      因此,为了找到第二,第三,第四项(指数1,2,3,值为2,-5,3)的总和,我们可以计算:

      A[3]-A[0] = 4 - 4 = 0
      

      所以你的问题现在减少到在数组A中找到最远的值,并且还有A [end]&gt; A [start]。

答案 2 :(得分:0)

您可以使用动态编程跟踪每个元素的11件事,从左向右移动。这11件事对应于以下可能的总和:
-5,-4,-3,-2,-1,0,1,2,3,4,5 对于这些中的每一个,您需要存储最左侧的索引,以便从该索引开始并在当前索引中结束的子阵列的总和给出这么多的总和。
这不是一个完整的解决方案,但我相信这可能有助于提示。