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

本文介绍了如何利用动态规划技术解决最大连续子序列和问题,包括详细的算法步骤、实例解析及代码实现,并对比了另一种分治策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述:

给定一个整数序列, 序列中可能有负数。 目的是找出这个序列的连续子序列(即子序列的元素的选取是连续的从序列中选取的)。即通过确定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).

运行结果为:


方法二: 使用divide and conquer, 具体参见算法导论中文第三版40页。 该方法编程参照如下:

http://fisherlei.blogspot.com/2012/12/leetcode-maximum-subarray.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值