找出一段序列,最大的连续子序列之和。
方法一:动态规划
这个题目实际上可以推导出来:data[]为序列,maxSum[i]为从0到i的最大连续子序列之和。
maxSum[i] = maxNumber(maxSum[i-1]+data[i],data[i]);
当然还需要对maxSum[0]做初始化,maxSum[0]= data[0];
最后从maxSum[i]种找到最大的一个数值就可以了,因为最大连续子序列,也许是在k位终止。
那么我们开始吧。
时间复杂度O(n);
function maxSeriesSum(data){
let maxSum = [];
maxSum[0] = data[0];
let Res = data[0];
const len = data.length;
for (let i=1; i<len; i++){
maxSum[i] = maxNumber(maxSum[i-1]+data[i],data[i]);
if (maxSum[i] > Res){
Res = maxSum[i];
}
}
return Res;
}
方法二:分治法
分治法求解 把序列分成左右两部分,一般对半分,数量不等也没关系。最大子序列和的位置存在三种情况:1、完全在左半部分;2、完全在右半部分;3、跨越左右两部分。分别求出左半部分的最大子序列和、右半部分的最大子序列和、以及跨越左右两部分的最大子序列和,三者中的最大者就是要求的。
左半部分的最大子序列和,可把左半部分作为新的输入序列通过该算法递归求出。右半部分的最大子序列和同理。
接着求解跨越左右两部分的最大子序列和,也就是求出包含左半部分中最右边元素的子序列的最大和,和包含右半部分中最左边元素的子序列的最大和,将两者相加即为跨越左右两个部分的最大子序列和。
具体见如下代码:
//分治算法
int a[999999];
int MaxSubSum(int left,int right)
{
int sum=0;
if(left==right)//基本情况:只有一个元素
sum=a[left]>0?a[left]:0;
else
{
int center=(left+right)/2;
int leftsum=MaxSubSum(left,center);//左半部分
int rightsum=MaxSubSum(center+1,right);//右半部分
//求包含左半部分最右元素的最大和
int s1=0;
int lefts=0;
for(int i=center;i>=left;i--)
{
lefts+=a[i];
if(lefts>s1) s1=lefts;
}
//求包含右半部分最左元素的最大和
int s2=0;
int rights=0;
for(int i=center+1;i<=right;i++)
{
rights+=a[i];
if(rights>s2) s2=rights;
}
//取三者最大值
sum=s1+s2;
if(sum<leftsum) sum=leftsum;
if(sum<rightsum) sum=rightsum;
}
return sum;
}