最大子序列和O(n)阶复杂度算法

问题描述给定整数序列A1,A2, A3,A4,A5,求(Ai + A(i+1) +.....Aj)的最大值:

int MostSon(int arryIn[],int len)
{
    int curSum = 0;
    int curStart =0;
    int most = 0;
    int end = 0;
    for(int index = 0;index < len;index++)
    {
        curSum += arryIn[index];
        if(curSum < 0)
        {
            curSum = 0;
            curStart = index + 1;
        }
        else
        {
            if(curSum >= most)
            {
                end = index;
                most = curSum;
            }
        }
    }
    return most;
}

算法解释:确定子序列最大值得关键点在于确定序列开始位置和结束位置。

开始位置难以确定,确定开始位置之后每加一个数字的SUM与SUM的前值最大的值,直到数列最后一个元素,即可获取SUM最大的值,和SUM最大时结束点的位置。

所以难点在于确定开始位置。

首先分析开始位置的特征。

例如数列 example[n],的最大子数列为example[s]到example[e]。

既然example[s]+。。。。example[e]最大,故example[s-1] +example[s]+。。。。example[e] < example[s]+。。。。example[e],

所以example[s-1]<0;更进一步example[i] +。。。example[s-1] < 0,0<= i <= s-1。

问题转化为求最大S,使得example[i] +。。。example[s-1] < 0,(0<= i <= s-1)。

具体思路:

从i= 0;开始sum + = sum +arryIn[i],依次累加只要sum的和为正值就继续累加,

如果sum < 0 ,则sum = 0,arryIn[i+1]重新累加直到 i 等于数组末尾。记下此时sum 累加的开始位即为最大子序列的最大位。

证明:如果sun累加过程中总共进行了N次清零操作,最后一次在S-1处,那么可以将数组分成N+1段,前N端累加值群为0,当i 处于子段前后端节点时 必然使得example[i] +。。。example[s-1] < 0,(0<= i <= s-1)。

当i不处于处于子段sub前后端节点时 而是处于子段sub内部节点时,i将子段sub分为前后两段,sub的累加值<0 ,又因为sub前半段必然>0,所以sub后半段累加值<0,所以example[i] +。。。example[s-1] < 0。至此证明完毕。

posted @ 2020-05-17 19:33  吃了吗世界  阅读(183)  评论(0)    收藏  举报