题目:
给你一个数组:1,12,-15,13,-2,6,求最大连续子序列和,这个题的答案是17,也就是13,-2,6
方法一(暴力法):
#include<iostream>//暴力法
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=1e5;
int arr[MAXN];
int MaxSubArray1(int n)//n3
{
int ans=0x80000000;//int最小值
for(int i=0;i<n;i++)//序头
{
for(int j=i;j<n;j++)//序尾
{
int sum=0;
for(int k=i;k<=j;k++)//遍历序头到序尾
{
sum+=arr[k];
}
ans=max(ans,sum);
}
}
return ans;
}
int MaxSubArray2(int n)//n2
{
int ans=0;
for(int i=0;i<n;i++)//序头
{
int sum=0;
for(int j=i;j<n;j++)//序尾
{
sum+=arr[j];
ans=max(ans,sum);
}
}
return ans;
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>arr[i];
cout<<MaxSubArray2(n)<<endl;
return 0;
}
这种方法不建议大家使用,容易超时,竟然我们学了算法,有没有用算法来解决的呢,当然是有的,我们来看一看法二;
方法二(分治法):
分治法也就是进行递归操作,也就是分而治之,将一个大问题分成很多个小问题,挨个挨个解决小问题,最后大问题就得到了解决;回到这个题,我们可以把这个序列分成一半,我们要解决的事,这个最大连续子序列和在这个分界点的两边,或者是中间,若是在两边的话那我们是否可以直接求出呢,如果在中间的话那么就求分界点前面的最大后缀和,和分界点后面的最大前缀和。然后递归一半的一半。。。问题就迎刃而解了。下面来看看代码吧。
#include<iostream>//分治法:从中间到两边,要么全在左边或者右边,要么跨立在中间,跨立在中间的只需要求一个前面的后缀和一个后面的前缀和
#include<cstdio>//复杂度为nlongn
#include<algorithm>
using namespace std;
const int MAXN=1e5;
int arr[MAXN];
int MaxAddArray(int from,int to)
{
if(to==from) return arr[to];
int middle=(to+from)>>1;
int m1=MaxAddArray(from,middle);
int m2=MaxAddArray(middle+1,to);
int left=arr[middle],sum=arr[middle];
for(int i=middle-1;i>=from;i--)//前面的后缀
{
sum+=arr[i];
left=max(left,sum);
}
int right=arr[middle+1];
sum=arr[middle+1];
for(int i=middle+2;i<=to;i++)//后面的前缀
{
sum+=arr[i];
right=max(right,sum);
}
int m3=left+right;
return max(max(m1,m2),m3);
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++) cin>>arr[i];
cout<<MaxAddArray(0,n-1)<<endl;
return 0;
}
当然我们这里的时间复杂度为O(nlogn),由于我的数学不好,在此就不证明了。那还有没有效率更高的代码呢,当然是有的。
方法三(分析法):
这里的分析法也就是动态规划,我对动态规划还不是特别熟悉,所以只在这里说一下思路。我们可以用sum存储的是前n项和,假设sum小于0,则不在i到j,在后面,而ans就是当前最大的值。
#include<iostream>
#include<cstdio>
using namespace std;
const int MAXN=1e5;
int arr[MAXN];
int main()
{
int n,sum=0,ans=0;
cin>>n;
for(int i=0;i<n;i++) cin>>arr[i];
for(int i=0;i<n;i++)
{
sum+=arr[i];
ans=max(ans,sum);
if(sum<0) sum=0;
}
return 0;
}
这个算法就是线性的,所以时间复杂度为O(n);