题目大意:给出一个包含k个整数的数组,求该数组的最大连续子序列。
解法思路:最简单的方法是暴力搜索,读入数据的同时构造前缀和数组,然后一个二层的循环做减法计算sum[i,j]表示下标i和j之间的整数和。但考虑到k最大为10000,二层循环在数据量较大的情况下会比较慢,时间也可能会不够(时限200ms)。
所以考虑到,读入数据后,当我们遍历到a[i]时,那么以a[i]为结尾的最大连续子序列,要么是在a[i-1]后面再续一个a[i],要么自己作为开头,所以这样只需一遍遍历,就可完成最大连续子序列和的求解。这样时间复杂度仅为O(n)。
注:题目还有一个要求,If all the K numbers are negative, then its maximum sum is defined to be 0, and you are supposed to output the first and the last numbers of the whole sequence.翻译过来是:“如果所有K个数都是负数,那么它的最大和被定义为0,你应该输出整个序列的第一个和最后一个数。”但实际数据应该是,当最后求出的最大和小于0时,才把最大和定义为0输出,并输出整个序列的第一个和最后一个数。因为我开始是按照题目要求在代码中加了个bool判断是否所有k个数都是负数,如果是负数则按要求输出,但发现最后还是有一个数据点出错。改成我自己认为合理的要求后,才AC掉。题目描述错了。
代码:
#include <iostream>
#include <limits.h>
using namespace std;
struct As
{
int maxsum; //表示包含当前位置的最大数列和
int head; //表示最大数列和的开头位置
};
int main()
{
int k;
cin>>k;
As a[10000];
int subs[10000];
bool B=true;
for(int i=0;i<k;i++)
{
cin>>subs[i];
if(subs[i]>0) B=false;
}
a[0].head=0;
a[0].maxsum=subs[0];
for(int i=1;i<k;i++)
{
if(a[i-1].maxsum+subs[i]>=subs[i])
{
a[i].maxsum=a[i-1].maxsum+subs[i];
a[i].head=a[i-1].head;
}
else
{
a[i].maxsum=subs[i];
a[i].head=i;
}
}
int headd,taill;
int answer=-INT_MAX;
for(int i=0;i<k;i++)
{
if(a[i].maxsum>answer)
{
headd=a[i].head;
taill=i;
answer=a[i].maxsum;
}
}
if(answer<0)
{
answer=0;
headd=0; taill=k-1;
}
cout <<answer<<" "<<subs[headd]<<" "<<subs[taill]<< endl;
return 0;
}