- 最大子序列和:
给定一个包含 K 个整数的序列 {N1,N2,…,NK}
连续子序列定义为 {Ni,Ni+1,…,Nj}
,其中 1≤i≤j≤K
最大子序列是指序列内各元素之和最大的连续子序列。
例如,给定序列 {−2,11,−4,13,−5,−2},它的最大子序列为 {11,−4,13},其各元素之和为 20
现在你需要求出最大子序列的各元素之和,并且输出最大子序列的第一个元素和最后一个元素的值。
输入格式
第一行包含一个整数 K
第二行包含 K个整数。
输出格式
输出一行三个整数,分别表示最大子序列的各元素之和以及最大子序列的第一个元素和最后一个元素的值。
设最大子序列为 {Ni,Ni+1,…,Nj}
,如果答案不唯一,则选择 i 更小的解,如果仍不唯一,则选择 j
更小的解。
注意,我们规定,如果所有 K个数字均为负数,则其最大和定义为 0,并且应该输出整个序列的第一个数字和最后一个数字。
数据范围
1≤K≤10000
序列内元素的绝对值不超过 10^5
输入样例:
10
-10 1 2 3 4 -5 -23 3 7 -21
输出样例:
10 1 4
思路1:前缀和+遍历
时间复杂度 O(n^2)
#include<iostream>
using namespace std;
const int N=100010;
int a[N],b[N];
int main(){
int n,m;
cin>>n;int max=-1;//避免出现最大子列和恰好为0,导致输出错误
int p,q;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=b[i-1]+a[i];
}
for(int i=0;i<n;i++){
for(int j=i+1;j<=n;j++){
if((b[j]-b[i])>max){
max=b[j]-b[i];
p=i+1;//注意边界问题
q=j;
}
}
}if(max>=0)cout<<max<<' '<<b[p]-b[p-1]<<" "<<b[q]-b[q-1]<<endl;
else cout<<0<<" "<<a[1]<<" "<<a[n]<<endl;
}
思路2:
时间复杂度 :O(n)
#include<iostream>
using namespace std;
const int N=10010;
int a[N],b[N];
int n,m;
int main(){
cin>>n>>m;int thismax=0,max=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
thismax+=a[i];
if(thismax>max){
m=a[i];
max=thismax;
}
else if(thismax<0)thismax=0;//当前子序列和为负,则不可能使后面和增大,抛弃
}cout<<max<<" "<<m;
for(;max!=0;m--){//已知最大子序列和的终止元素,倒推起始元素
max-=a[m];
}
cout<<a[m+1]<<endl;
}
思路3:
时间复杂度:O(n)
#include<iostream>
using namespace std;
const int N=10010;
int a[N];
int n,m,p;
int main(){
cin>>n;int thismax=0,
max=-1,
j=0,//记录序列小于0元素个数
len=0;//记录最大子序列和的元素个数
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
thismax+=a[i];
len++; if(thismax>max){
m=a[i];
p=a[i-len+1];
max=thismax;}
if(thismax<0){thismax=0;len=0;}//当前子序列和为负,则不可能使后面和增大,抛弃
if(a[i]<0)j++;
}
if(j==n)cout<<0<<' '<<a[1]<<' '<<a[n]<<endl;
else { cout<<max<<' '<<p<<' '<<m<<endl;}}
搞到半夜才把复杂度降到O(n),太难了。。。。。