【问题标题】:Maximum Countiguous Negative Sum or Mnimum positive subsequence sum problem最大连续负和或最小正子序列和问题
【发布时间】:2011-10-03 18:38:27
【问题描述】:

我们都听说过宾利漂亮的编程珍珠问题 它解决了最大子序列和:

maxsofar = 0;
maxcur = 0;
for (i = 0; i < n; i++) {
  maxcur = max(A[i] + maxcur, 0);
  maxsofar = max(maxsofar, maxcur);
}

如果我们添加一个小于 M 的附加条件最大子序列会怎样?

【问题讨论】:

    标签: algorithm max programming-pearls


    【解决方案1】:

    应该这样做。我是赖吗?

    int maxsofar = 0;
    for (int i = 0; i < n - 1; i++) {
       int maxcur = 0;
       for (int j = i; j < n; j++) {
          maxcur = max(A[j] + maxcur, 0);
          maxsofar = maxcur < M ? max(maxsofar, maxcur) : maxsofar;
       }
    }
    

    不幸的是,这是O(n^2)。当maxcur &gt;=M 仍然存在时,您可以通过打破内部循环来加快速度,但n^2 仍然存在。

    【讨论】:

    • M = 8, A={ 2, 3, 4, 5}。你会给 5 而不是 7。
    【解决方案2】:

    这可以使用动态规划来解决,尽管只能在伪多项式时间内解决。

    定义

    m(i,s) := maximum sum less than s obtainable using only the first i elements
    

    那么你可以使用下面的递推关系计算max(n,M)

    m(i,s) = max(m(i-1,s), m(i-1,s-A[i]]+A[i]))
    

    这个解法类似于背包问题的解法。

    【讨论】:

      【解决方案3】:

      如果所有A[i] &gt; 0,您可以在O(n lg n) 中执行此操作:预先计算部分和S[i],然后对S 进行二进制搜索S[i] + M。例如:

      def binary_search(L, x):
        def _binary_search(lo, hi):
          if lo >= hi: return lo
          mid = lo + (hi-lo)/2
          if x < L[mid]:
            return _binary_search(lo, mid)
          return _binary_search(mid+1, hi)
        return _binary_search(0, len(L))
      
      A = [1, 2, 3, 2, 1]
      M = 4
      S = [A[0]]
      for a in A[1:]:
        S.append(S[-1] + a)
      maxsum = 0
      for i, s in enumerate(S):
        j = binary_search(S, s + M)
        if j == len(S):
          break
        sum = S[j-1] - S[i]
        maxsum = max(sum, maxsum)
      print maxsum
      

      编辑:正如 atuls 正确指出的那样,二分搜索是多余的;由于 S 在增加,我们可以只跟踪 j 每次迭代并从那里前进。

      【讨论】:

      • 它也是负面的。什么是 S[i]+M?
      • 进行了编辑以使其更清晰 - 但不,这没有考虑到否定A[i] 的可能性;二进制搜索不起作用。
      • 你不需要二分查找,线性查找就好。整个循环将在 O(n) 内完成,因为下一个搜索在上一个搜索的右侧。但仍然不适用于负数。
      【解决方案4】:

      可在 O(n log(n)) 内求解。使用二叉搜索树(平衡)搜索大于 sum-M 的最小值,然后从左到右更新 min 并插入 sum。其中 sum 是到目前为止的部分总和。

        best = -infinity;
        sum = 0;
        tree.insert(0);
        for(i = 0; i < n; i++) {
           sum = sum + A[i];
           int diff = sum - tree.find_smallest_value_larger_than(sum - M);
           if (diff > best) {
             best = diff;
           }
           tree.insert(sum);
         }
      
         print best
      

      【讨论】:

      • 嗯。我想知道这个问题是否可以简化为比较排序,在这种情况下 O(n lg n) 将是一个紧密的界限......
      猜你喜欢
      • 1970-01-01
      • 2014-10-31
      • 2023-03-27
      • 2017-03-12
      • 2022-12-12
      • 2015-10-31
      • 2019-08-22
      • 1970-01-01
      • 2021-01-21
      相关资源
      最近更新 更多