题目链接->link
问题描述
给定一个整数序列,其中有正有负,求其最长子序列的和,以及该子序列对应的首、尾元素,如果序列全为负数,那么则输出和为0,以及整个序列的首、尾元素。
思路分析
- 设置当前和thisSum和最大和maxSum,设置leftIndex,rightIndex记录最大子序列左、右下标,设置tempLeft记录临时左下标。
- 循环输入序列元素,令thisSum=thisSum+a[i],因为是连续子序列,如果当前和为负数,那么不可能令后面的子序列和增大,所以应舍弃,将thisSum记为0,并更新tempLeft。
- 否则,则判断当前和是否大于最大和,如果大于,更新最大和、左下标和右下标的值。
代码实现
#include "cstdio"
#include "iostream"
using namespace std;
int main(){
int n;
scanf("%d",&n);
int a[n];
int maxSum=-1,thisSum=0,leftIndex=0,rightIndex=n-1,tempLeft=0;
for(int i=0;i<n;i++){
scanf("%d",&a[i]);
thisSum+=a[i];
if(thisSum<0){
thisSum=0;
tempLeft=i+1;
}
else if(maxSum<thisSum){
maxSum=thisSum;
leftIndex=tempLeft;
rightIndex=i;
}
}
if(maxSum<0)
maxSum=0;
printf("%d %d %d\n",maxSum,a[leftIndex],a[rightIndex]);
return 0;
}
复杂度分析
- 如果暴力法求所有子序列和再比较,需要O(n2)。
- 如果用分治法,递归思想,从中间分成两个子序列,递归地求左子序列最大长度和右子序列最大长度,以及跨越中间线的最大子序列和,三者中最大的即所求,需要O(nlog2n)。
- 如果用动态规划的思想,在线处理,利用连续子序列和增长的性质,则只需要O(n)。