最大连续子序列和


问题:
已知 一个整数序列a[n]:n个整数(有正负)
求 在这个序列的所有子序列(连续)中,最大的和是多少?

注意:
以下代码都要求最大和 【可为负数】,若要求最大和 【非负】,只需最后判断一下即可

一、贪心思想

假设a[l]...a[r]的和为 sum
如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留
如果 sum < 0,则说明 sum 对结果无增益效果,需要舍弃

 

明白了这个道理,那么对于第i个数来说,我们查看他之前的sum,如果sum<0,那么当前的最大连续子序列和就是它本身(舍弃前面的);如果sum>0,那么当前的最大和就是sum+a[i]  (sum保留了)

sum=0的情况都保留和丢弃都可以

    int ans=a[1];  //ans初始化为第一个元素,不能是0,因为最大值可能是负数
    int sum=0;
	for (int i=1; i<=n; i++){
		if(sum>=0) sum+=a[i];
        	else sum=a[i];  
		ans=max(ans,sum);
	}

二、动态规划

用f[i]表示以第i个数a[i]结尾的最大子序列和。

那么f[i]的状态转移方程也很好得出,对于a[i]是单独算还是加入前面的f[i-1],即:f[i]=max(f[i-1]+a[i],a[i])

问:为什么会想到用f[i]表示以第i个数a[i]结尾的最大子序列和?

连续的子序列的和,这是关键,只有f[i]包含了a[i],递推才可以进行下去,不然就不连续了。

代码:用ans代替f[i]的迭代,省空间。

	int ans=a[1],sum=0;
	for (int i=1; i<=n; i++){
		sum=max(sum+a[i],a[i]);
		ans=max(ans,sum);
	}

三、分治思想≈线段树

对于一个区间 [l, r],我们可以维护四个量:

lSum 表示 [l, r] 内以 l 为左端点的最大子段和
rSum 表示 [l, r] 内以 r 为右端点的最大子段和
mSum 表示 [l, r] 内的最大子段和
iSum 表示 [l, r] 的区间和

然后转移条件,相当于线段树:

首先最好维护的是 iSum,区间 [l, r] 的 iSum 就等于「左子区间」的 iSum 加上「右子区间」的 iSum。
对于 [l, r] 的 lSum,存在两种可能,它要么等于「左子区间」的 lSum,要么等于「左子区间」的 iSum 加上「右子区间」的 lSum,二者取大。
对于 [l, r] 的 rSum,同理,它要么等于「右子区间」的 rSum,要么等于「右子区间」的 iSum 加上「左子区间」的 rSum,二者取大。
当计算好上面的三个量之后,就很好计算 [l,r] 的 mSum 了。我们可以考虑 [l,r] 的 mSum 对应的区间是否跨越 m——它可能不跨越 m,也就是说 [l,r] 的 mSum 可能是「左子区间」的 mSum 和 「右子区间」的 mSum 中的一个;它也可能跨越 m,可能是「左子区间」的 rSum 和 「右子区间」的 lSum 求和。三者取大。
 

PS:线段树的学习和使用:【未完成】线段树的学习和使用_马小超i的博客-CSDN博客_线段树的使用

class Solution {
public:
    struct Status {
        int lSum, rSum, mSum, iSum;
    };
 
    Status pushUp(Status l, Status r) {
        int iSum = l.iSum + r.iSum;
        int lSum = max(l.lSum, l.iSum + r.lSum);
        int rSum = max(r.rSum, r.iSum + l.rSum);
        int mSum = max(max(l.mSum, r.mSum), l.rSum + r.lSum);
        return (Status) {lSum, rSum, mSum, iSum};
    };
 
    Status get(vector<int> &a, int l, int r) {
        if (l == r) return (Status) {a[l], a[l], a[l], a[l]};
        int m = (l + r) >> 1;
        Status lSub = get(a, l, m);
        Status rSub = get(a, m + 1, r);
        return pushUp(lSub, rSub);
    }
 
    int maxSubArray(vector<int>& nums) {
        return get(nums, 0, nums.size() - 1).mSum;
    }
};
 

并非原创!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值