【问题标题】:count the sequence that has the max sum in array O(N)计算数组 O(N) 中总和最大的序列
【发布时间】:2015-01-07 08:03:45
【问题描述】:

如果我想计算数组中具有最大总和的序列,当我有 O(n) 时间复杂度的限制时,我该怎么做?

例如:{1,2,3,4,-3} 输出将是 4,因为 1+2+3+4 的和是最大和,并且该序列中有 4 个数字

我知道如何使用 O(N^2) 时间复杂度但不使用 O(n) 帮助? :)

【问题讨论】:

  • 如果你有求和的序列直到原始序列中的那个点,那么你能解决它吗?例如:{1,2,3,4,-3} 作为原始序列将产生:{1,3,6,10,7}。您可以在 O(n) 时间内从原始序列到求和序列。现在从求和的一个到 O(n) 中最大序列的长度也是如此..
  • 如果有多个这样的子数组,输出是什么?

标签: algorithm math time-complexity


【解决方案1】:

我认为你可以这样迭代:

MaxSum = 0;
CurrentSum = 0;
MaxLen = 0;
CurrentLen = 0;

Index = GetFirstPositiveValue(); 
// This function returns the first Index where Array[Index] > 0
// O(n) 

while (Index < Array.Length()) {
    // general loop to parse the whole array
    while (Array[Index] > 0 && Index < Array.Length()) {
        CurrentSum += Array[Index];
        CurrentLen++;
        Index++
    }
    // We computed a sum of positive integer, we store the values 
    // if it is higher than the current max
    if (CurrentSum > MaxSum) {
        MaxSum = CurrentSum;
        MaxLen = CurrentLen;
    }
    // We reset the current values only if we get to a negative sum
    while (Array[Index] < 0 && Index < Array.Length()) {
        CurrentSum += Array[Index];
        CurrentLen++;
        Index++;
    }
    //We encountered a positive value. We check if we need to reset the current sum
    if (CurrentSum < 0) {
        CurrentSum = 0;
        CurrentLen = 0;
    }
}
// At this point, MaxLen is what you want, and we only went through 
// the array once in the while loop.

从第一个正面元素开始。如果每个元素都是负数,那么就选择最高的,问题就结束了,这是一个1元素序列。

只要我们有正值,我们就会继续求和,所以我们有一个当前的最大值。当我们有负数时,我们检查当前最大值是否高于存储的最大值。如果是这样,我们将存储的最大值和序列长度替换为新值。

现在,我们对负数求和。当我们发现另一个阳性时,我们必须检查一下:

如果当前总和是正数,那么我们仍然可以使用这个序列获得最大总和。如果它是负数,那么我们可以丢弃当前的总和,因为最大总和不会包含它:

在{1,-2,3,4}中,3+4大于1-2+3+4

只要我们没有遍历整个数组,我们就会重新开始这个过程。只有当我们有一个产生负和的子序列时,我们才会重置序列,并且只有当我们有更大的值时才会存储最大值。

我认为这按预期工作,我们只遍历数组一两次。所以它是 O(n)

我希望这是可以理解的,我很难说清楚我的想法。使用 {1,2,3,-4,5} / {1,2,3,-50,5} / {1,2,3,-50,4,5} 等小示例执行此算法可能会有所帮助如果我不够清楚:)

【讨论】:

    【解决方案2】:

    如果您知道长度为 N 的数组末尾的子数组的最大和,则可以简单地计算长度为 N+1 之一的子数组:

    [..., X]       has max subsum S
    [..., X, Y]    has max subsum max(0, S + Y)
    

    因为您包含 Y 或者您有一个空子数组(因为子数组位于列表的末尾)。

    您可以通过从一个空列表构建它来找到以 any 位置结尾的子数组的所有最大总和:

    []             S = 0
    [1]            S = 1
    [1, 2]         S = 3
    [1, 2, -4]     S = 0
    [1, 2, -4, 5]  S = 5
    

    然后您只需要跟踪最大值及其宽度。这是一些演示该算法的 Python 代码。

    def ranges(values):
        width = cum_sum = 0
    
        for value in values:
            cum_sum += value
            width += 1
    
            if cum_sum < 0:
                width = cum_sum = 0
    
            yield (cum_sum, width)
    
    total, width = max(ranges([-2, 1, 2, 3, -8, 4, -3]))
    
    total, width
    #>>> (6, 3)
    

    【讨论】:

      猜你喜欢
      • 2020-02-09
      • 1970-01-01
      • 2015-05-25
      • 2015-08-22
      • 2018-08-09
      • 2011-12-22
      • 2020-09-24
      • 1970-01-01
      • 2012-09-08
      相关资源
      最近更新 更多