最大连续和的四种解法

来源:互联网 发布:linux 重置网络配置 编辑:程序博客网 时间:2024/06/04 19:09

最大连续和问题:
给出一个长度为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]);
0 0