1、题目描述
求一个序列的最大子段和即最大连续子序列之和
2、枚举法
枚举变量:每一段的起点和终点
枚举范围:起点:1- n,终点:起点-n;
判断条件:找最大值即可
复杂度:O(NNN)
#include<iostream>
using nampespace std;
int a[20005];
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];}
int maxx=-0x7fffffff;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int sum=0;
for(int k=i;k<=j;k++)
{
sum+=a[k];}
if(sum>maxx)
maxx=sum;
}
}
}
cout<<maxx<<endl;
return 0;
}
3、优化(减少重复计算)
序列从i 到 j 的一段和可以表示为从头到 j 的和减去从 从头到 i 段的和,最后再加上 a[i];
s[i-j]=s[j]-s[i]+a[i]
复杂度:O(N*N)
#include<iostream>
using nampespace std;
int a[20005];
int s[20005]={0}
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
s[i]=s[i-1]+a[i];
}
int maxx=-0x7fffffff;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
int sum=0;
sum+=s[j}-s[i]+a[i];
if(sum>maxx)
maxx=sum;
}
}
}
cout<<maxx<<endl;
return 0;
}
4、分治解法(二分)
假设序列对应区间[l,r],其之间为mid,则最大子序列 [i,j] 有以下三种情况:
1、l<=i<=j<=mid;
2、i<=mid<=j<=r;
3、mid<=i<=j<=r;
分别取出这三种情况的值,再取他们的最大值;
复杂度:O(n)
首先,求区间[i … mid]最大值和区间[mid … j]最大值,也就是求以mid为头的序列最大值和以mid为尾。
首先以mid为头的序列最大值:
int maxx2=-0x7fffffff;
int sum2=0;
for( int k=mid;k<=j;k++)
{
sum2+=a[k];
maxx2=max(sum2,maxx2)
}
以mid为尾:
int maxx1=-0x7fffffff;
int sum2=0;
for( int k=mid;k>=i;k--)
{
sum1+=a[k];
maxx2=max(sum1,maxx1)
}
递归的终止条件:1、递归的区间为解;2、递归的区间只有一个元素
#include<iostream>
using namespace std;
int a[20005];
int find(int l,int r){
if(l==r) return a[l];
int mid =(l+r)/2;
//以mid为头的序列最大值:
int maxx2=-0x7fffffff;
int sum2=0;
for( int k=mid;k<=r;k++)
{
sum2+=a[k];
maxx2=max(sum2,maxx2)
}
//以mid为尾:
int maxx1=-0x7fffffff;
int sum2=0;
for( int k=mid;k>=l;k--)
{
sum1+=a[k];
maxx2=max(sum1,maxx1)
}
return max(max(find(l,mid),find(mid+1,r)),maxx1+maxx2-a[mid]);
int main(){
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
cout<<find(1,n)<<endle;
return 0;
5、贪心解法
若a[i-1]序列>0,则 s[i]+a[i-1]序列>a[i];
反之,若a[i-1]<0; 则不需要加上i-1前面的序列
假设必须选择a[i], 贪心过程的最优解就是以a[i]为结尾的子序列和s[i]最大的局部最优解.
#include<iostream>
using namespace std;
int a[20005];
int main()
{
int n;
cin>>n;
for(int i=1; i<=n;i++)
cin>>a[i];
int sum=a[1];
int maxx=a[1];
for(int i=2;i<=n;i++)
{
if(sum<0) sum=0
sum +=a[i];
maxx=max(sum,maxx)
}
cout<<maxx<<endle;
return 0;
6、动态规划
假设f[i]表示以第 i 个元素结尾的最大子序列的最大值,则:
f[i]=max(f[i-1]+a[i],a[i])
初始状态: f[1]=a[1]
#include<iostream>
using namsespace std;
int a[20005];
int f[20005];
int main()
{
int n;
cin>>n;
for(int i=1; i<=n;i++)
cin>>a[i];
f[1]=a[1];
int maxx=f[1];
for(int i=2;i<=n;i++)
{
f[i]=max(f[i-1]+a[i],a[i]);
maxx=max(f[i],maxx)
}
cout<<maxx<<endle;
return 0;