经典算法————求最大子列和
题目:
最大连续子数列和一道很经典的算法问题,给定一个数列,其中可能有正数也可能有负数,我们的任务是找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大。我们一起用多种方式,逐步优化解决这个问题。
为了更清晰的理解问题,首先我们先看一组数据:8-2 6 -1 5 4 -7 2 3
输出 14
题解:1。复杂度为n的3次方的算法,i为左端,j为右端,k从i到j循环求和
代码:#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
int shu[30];
int maxn=0,n;
cin>>n;
for(int i=0; i<n; i++)
cin>>shu[i];
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+=shu[k];
maxn=max(maxn,sum);
}
}
}
cout<<maxn<<endl;
return 0;
}
2.利用前一项的基础进行求和,每求一项均进行比较,复杂度为n的平方
代码:#include<algorithm>
#include<iostream>
using namespace std;
int main()
{
int shu[30];
int maxn=0,n;
cin>>n;
for(int i=0; i<n; i++)
cin>>shu[i];
for(int i=0; i<n; i++)
{
int sum=0;
for(int j=i; j<n; j++)
{
sum+=shu[j];
maxn=max(maxn,sum);
}
}
cout<<maxn<<endl;
return 0;
}
3.分治法:将原序列切成3个部分(时间复杂度为n*logn)(空间复杂度为n)
1.从中间到左侧这一部分找出最大值
2.从中间到右侧找出最大值,
3.从中间扫描到最左侧求出最大部分再与从中间扫面到右侧部分求出最大部分加和,最后利用递归找出这三者最大值
(注意:避免重复加middle,在右侧计算中要加入middle+1)
代码:
#include<algorithm>
#include<iostream>
using namespace std;
int shu[30];
int fen(int left,int right)
{
int middle=(left+right)/2;
if(left==right)
if(shu[left]<0) return 0;
else return shu[left];
int maxleft=fen(left,middle);//左侧最大值
int maxright=fen(middle+1,right);//右侧最大值
int leftsum=0,maxn=0;
for(int i=middle;i>=0;i--)
{
leftsum+=shu[i];
if(leftsum>maxn) maxn=leftsum;
}
leftsum=maxn;//扫描之后左侧最大值
int rightsum=0;
maxn=0;
for(int i=middle+1;i<=right;i++)//注意为middle加1,避免重复加
{
rightsum+=shu[i];
if(rightsum>maxn) maxn=rightsum;
}
rightsum=maxn;//扫描之后右侧最大值
return max(max(maxleft,maxright),leftsum+rightsum);
}
int main()
{
int maxn=0,n;
cin>>n;
for(int i=0; i<n; i++)
cin>>shu[i];
maxn=fen(0,n-1);
cout<<maxn<<endl;
return 0;
}
4.在线处理(逐个判,如果sum<0,更新然后重新算)
#include<algorithm>
#include<iostream>
using namespace std;
int shu[30];
int main()
{
int maxn=0,n;
cin>>n;
for(int i=0; i<n; i++)
cin>>shu[i];
int sum=0;
for(int i=0;i<n;i++)
{
sum+=shu[i];
if(sum>maxn) maxn=sum;
if(sum<0) sum=0;
}
cout<<maxn<<endl;
return 0;
}
浙公网安备 33010602011771号