1)首先最簡單的就是模擬時間複雜度是O(n^3)
/*
最大連續和問題
O(n^3)
*/
#include<cstdio>
#include<iostream>
using namespace std;
int main() {
int a[1005],n,sum,ans;
while(~scanf("%d",&n)) {
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
ans=a[1];
int cnt=0;
for(int i=1; i<=n; i++)
for(int j=i; j<=n; j++) {
sum=0;
for(int k=i; k<=j; k++)
{
sum+=a[k];
cnt++;
}
ans=max(ans,sum);
}
printf("ans=%d cnt=%d\n",ans,cnt);
}
}
2)將上述的代碼優化一點點,運用樹狀數組的思想求子序列的和爲兩個前綴和之差
時間複雜度爲O(n^2)相對於上面的3次方的時間複雜度優化了不少。
/*
最大連續和,運用:子序列和等於兩個前綴和之差
O(n^2)
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int a[1005],ans,n,s[1005];
while(~scanf("%d",&n)) {
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
s[0]=0;
ans=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++)
ans=max(ans,s[j]-s[i-1]);
printf("%d\n",ans);
}
}
3)接下來還可以將2次方是時間複雜度再次優化,那就是用分治法。
時間複雜度爲O(nlogn),相比較而言又優化了很多
/*
分治法求最大連續和問題
分治法的三個步驟:
1)劃分問題:把問題的實例化成子問題
2)遞歸求解:遞歸解決子問題
3)合併問題:合併子問題的解,得到原問題的解
O(nlogn)
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[1005];
int maxsum(int *a,int x,int y) { //返回在數組中左閉右開[x,y)的最大連續和(空區間可表示爲[x,x))
int v,l,r,maxs;
if(y-x==1) return a[x];//如果只有一個元素,直接返回;
int m=x+(y-x)/2;//第一步,劃分成[x,m),[m,y);
//此處用x+(y-x)/2,而不用(x+y)/2,'/'總是朝0方向取整,而不是向下取整,此處的方式可以保證分界點總是靠近區間起點。
maxs=max(maxsum(a,x,m),maxsum(a,m,y));//第二步:遞歸求解子問題
//第三步:合併;
v=0,l=a[m-1];//從分界點開始往左的最大連續和l;
for(int i=m-1; i>=x; i--)
l=max(l,v+=a[i]);
v=0,r=a[m];//從分界點開始往右的最大連續和r;
for(int i=m; i<y; i++)
r=max(r,v+=a[i]);
return max(maxs,l+r);
}
int main() {
int n;
while(~scanf("%d",&n)) {
for(int i=1; i<=n; i++)
scanf("%d",&a[i]);
printf("%d\n",maxsum(a,1,n+1));
}
}