【CRR算法笔记】基础算法-最大连续子序列之和

178 阅读2分钟

找出一段序列,最大的连续子序列之和。

方法一:动态规划

这个题目实际上可以推导出来: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;
}