首页 > 代码库 > dynamic programming 之Maximum Sub-Sequence Sum(最大子序列和问题)

dynamic programming 之Maximum Sub-Sequence Sum(最大子序列和问题)

问题描述:

给定一个整数序列, 序列中可能有负数。 目的是找出这个序列的连续子序列(即子序列的元素的选取是连续的从序列中选取的)。即通过确定i, j 的值,  使得的值达到最大。 我们定义, 当所有的元素为负数值的时候, 那么maximum subsequence sum 为0。


下面我们用动态规划的技术去求解。

为了找到最大连续子序列和,  不难看出, 在扩展我们的求和窗口的时候, 当新加进窗口的元素市负数的时候, 只要我们得到的新的求和窗口的值求和不是负数, 那么我们就不能丢掉这个新的负数。 也就是我们就不应该去重新的从新元素的下个元素开始重新开辟新的窗口(如果是这种情况, 我们的旧的窗口的求和的最大值已经被保存下来)。 之所以如此是因为只要我们的求和窗口是真的, 我们就有理由期望后面的元素的假如会得到更大的maximum subsequence sum。


我们知道, 能够使用动态规划去求解的问题满足两个原则。 一个是这个问题必须具有最优子结构(optimal substructure), 这个性质说的是可以通过求解子问题的最优解, 然后combine 称为我们的optimal solution。

第二个性质是递归(recursion), 或者也可以说成是重叠子问题(overlapping subproblem)。

动态规划算法的实现主要有两种方式, 一种是bottom-up, 一种是top-down。

下面我们介绍的是bottom-up 实现动态规划。

具体步骤如下:

记S[i] 为maximum subsequence sum till i-th element。

公式如下:


由上面的公式可知, S[i]取的是要么是A[i], 要么是i-1(包含)前面的maximum susequence sum 和A[i] 之和。 我们可以通过判断S[i-1] 是否小于0来做出判断是否需要重新开辟从A[i] 为起点的新的窗口。


举个例子, 假如序列为-2, -3, 4, -1, -2, 1, 5, -3 如下:


所以, 最终我们找到这个序列的maximum subsequence 为7。

#include <iostream>
#include <vector>

using namespace std;

int maxSubSum(const vector<int> &a) {
    int maxSum = 0;
    int thisSum = 0;
    for (int j = 0; j < static_cast<int>(a.size()); j++) {
        thisSum += a[j];
        if(thisSum > maxSum) {
            maxSum = thisSum;
        }
        else if(thisSum < 0) { // eliminate negative prefix
            thisSum = 0;
        }
    }
    return maxSum;

}

int main()
{
    vector<int> myArr = {-2, -3, 4, -1, -2, 1, 5, -3};
    cout << maxSubSum(myArr) << endl;

    return 0;
}

算法分析如下:时间复杂度为O(N)。空间复杂去为O(1).

运行结果为:



dynamic programming 之Maximum Sub-Sequence Sum(最大子序列和问题)