最大连续和的四种解法

最大连续和问题:
给出一个长度为n的序列A1,A2,A3,…An,求最大连续和。
即:找到1<=i<=j<=n,使Ai+A(i+1)+…+An尽量大

解法1:

//枚举所有连续子序列,Tn=O(n^3)
int maxn=A[1];
for(int i=1;i<=n;i++)
    for(int j=i;j<=n;j++){
        int sum = 0;
        for(int k=i;k<=j;k++)
            sum+=A[k];
        if(sum>maxn)
            maxn=sum; 
    }

解法2:

/*
定义Si=A1+A2+...+Ai,则Ai+A(i+1)+...Aj=Sj-S(i-1)。
可据此求解本题,Tn=O(n^2)。
*/
A[0]=S[0]=0;
int maxn=A[1];
for(int i=1;i<=n;i++)
    S[i]=S[i-1]+A[i];
for(int i=1;i<=n;i++)
    for(int j=i;j<=n;j++)
        if(S[j]-S[i-1]>maxn)
            maxn=S[j]-S[i-1];


解法3

*
分治法。
分治算法一般分为3个步骤:
1.划分问题:把问题的实例划分为子问题。
2.递归求解:递归解决子问题。
3.合并问题:合并子问题的解得到原问题的解。
本题中,“划分”就是把序列分成元素个数尽量相等的两半;“递归求解”就是分别求出完全位于左半或
完全位于右半的最佳序列;“合并”就是求出起点位于左半、终点位于右半的最大连续和序列,并和子问题
的最优解比较。
*/
int get_maxn(int *A,int begin,int end){
//返回A数组在左闭右开区间[begin,end)的最大连续和
if(end-begin==1)
return A[begin];
int mid=(begin+end)/2;
int maxn=max(get_maxn(A,begin,mid),get_maxn(A,mid,end));
int left=A[mid-1],right=A[mid];
//left表示以mid-1为终点往左的最大连续和,right表示以mid为起点往右的最大连续和
int v=0;
for(int i=mid-1;i>=begin;i–) left=max(left,v+=A[i]);
v=0;
for(int i=mid;i


解法4:

/*
解法2的改进:当j确定时,S[j]-S[i-1]最大,相当于S[i-1]最小,
用min_a[i]表示A1,A1+A2,A1+A2+A3,...A1+A2+...Ai中的最小值,即A1到Ai的最小前缀和
*/
int min_a[n];
S[0]=A[0]=0;
min_a[0]=0;
for(int i=1;i<=n;i++){
    S[i]=S[i-1]+A[i];
    min_a[i]=min(min_a[i-1],min_a[i-1]+A[i]);
}
int ans=A[1];
for(int i=1;i<=n;i++)
    ans=max(ans,S[j]-min_a[i-1]);
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值