题目:
给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。
要求算法的时间复杂度为O(n)。
输入格式:
输入有两行:
第一行是n值(1<=n<=10000);
第二行是n个整数。
输出格式:
输出最大子段和。
输入样例:
在这里给出一组输入。例如:
6
-2 11 -4 13 -5 -2
输出样例:
在这里给出相应的输出。例如:
20
算法描述:
采用一维填表法 。
难点:不知道什么时候结束
设:
a[] :存数
s[i]: 以a[i]为结尾的最大字段和
则可以得到数组元素之间的关系:
if s[i-1]<=0 s[i]=a[i]
if s[i-1]>0 a[i]+s[i-1]
代码:
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
int a[n];
int s[n]={0};// s[i]:以第i个数结尾的最大子段和
int flag=0;// 记录负数的个数的
for(int i=0;i<n;i++){
cin>>a[i];
if(a[i]<0) flag++;
}
if(flag==n) cout<<0;//当所给的整数均为负数时,定义子段和为0。
else{
s[0]=a[0];
for(int i=1;i<n;i++){
if(s[i-1]<=0) s[i]=a[i];
else s[i]=s[i-1]+a[i];
}
int max=s[0];
for(int i=0;i<n;i++){
if(max<s[i]) max=s[i];
}
cout<<max;
}
}
进一步引申思考:
如何找到最大子序列是哪几个构成的?
不难发现,我们只要把递推关系式逆过来就行了。
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin>>n;
int a[n];
int s[n]={0};// s[i]:以第i个数结尾的最大子段和
int flag=0;// 记录负数的个数的
for(int i=0;i<n;i++){
cin>>a[i];
if(a[i]<0) flag++;
}
if(flag==n) cout<<0;//当所给的整数均为负数时,定义子段和为0。
else{
s[0]=a[0];
for(int i=1;i<n;i++){
if(s[i-1]<=0) s[i]=a[i];
else s[i]=s[i-1]+a[i];
}
int max=s[0],index=-1;
for(int i=0;i<n;i++){
if(max<s[i]){
max=s[i];
index=i;
}
}
cout<<max<<endl;
// 改一改题:
//并要输出最大子段和所对应的子段
stack<int> child;
for(int i=index;i>=0;i--){
if(s[i-1]<=0){
child.push(a[i]);
break;
}
else child.push(s[i]-s[i-1]);
}
cout<<"下面输出最大子段和所对应的子段序列:"<<endl;
while(!child.empty()){
cout<<child.top()<<" ";
child.pop();
}
}}
改进后的运行结果: