最大子序列求和详解

主要是课堂PPT上的内容,但是觉得很有启发意义,遂记录下来

题目

给定(可能是负的)整数序列A1,A2。。。An,寻找(并标识)值为最大的序列。如果所有的整数都是负的,那么最大连续子序列的和是零。

例如,假设输入是{-2, 11, -4, 13, -5, 2},那么答案是20,它表示连续子序列包含了第2项到第4项(如粗体字部分)。又如第二个例子,对于输入{1, -3, 4, -2, -1, 6},答案是7,这个子序列包含最后四项。

解一:穷举法

思路:

分别求子序列

[0,0],[0,1],。。。,[0,n]

[1,1],[1,2],。。。[1,n]

。。。

[n,n]

的和,求出最大值

代码

int maxSubsequenceSum(int a[], int size, int &start, int &end)
 {  int maxSum = 0;
    for (int i = 0; i < size; i++ )
        for( int j = i; j < size; j++ )
            {  int thisSum = 0;
               for( int k = i; k <= j; k++ )
                   thisSum += a[ k ];
               if( thisSum > maxSum )
                    {  maxSum = thisSum;
                       start = i;   end = j;
                    }
             }
 return maxSum;
}

算法分析

最里层的语句thisSum += a[ k ];在最里层循环中执行j-i+1次。第二个循环的规模是n-i,最外层的循坏规模是n。因此最里层语句执行的次数是

即O(n3)

解二:穷举法的优化

思路

最内层循环已经包含在第二层循环内,所以可以省略

代码

int maxSubsequenceSum(int a[], int size, int &start, int &end)
  {  int maxSum = 0;
     for( int  i = 0; i < size; i++ ){ 
           int thisSum = 0;
           for( int j = i; j < size; j++ ){  
               thisSum += a[j];
               if( thisSum > maxSum ){
                  maxSum = thisSum;
                  start = i;   end = j;
                 }
              }
        }

     return maxSum;
 }

算法分析

少了内层循环的n次遍历,所以时间复杂度为O(n2)

解三:O(n)规模的遍历

思路

如果一个子序列的和是负的,则它不可能是最大连续子序列的一部分,因为我们可以通过不包含它来得到一个更大的连续子序列。如:{-2, 11, -4, 13, -5, 2}的最大子序列不可能从-2开始;{1, -3, 4, -2, -1, 6}的最大子序列不可能包含{1,-3}

所有与最大连续子序列毗邻的连续子序列一定有负的(或0)和(否则会包含它们)。

在算法二中,当检测出一个负的子序列时,不但可以从内层循环中跳出来,而且还可以让i直接增加到j+1。如:{1, -3, 4, -2, -1, 6},当检测序列[1,-3]后,发现是负值,则表示该子序列不可能包含在最大子序列中。因此,接下去就可以从4开始检测。

注意:当检测序列[1,-3]后,可以确定他不在最大子序列中,但1仍可能是最大子序列,如果-3后面都是负值。因此在找到新的最大子序列前,必须保存1是最大子序列的事实。

代码

int maxSubsequenceSum(int a[], int size, int &start, int &end){ 
   int maxSum = 0,  thisSum = 0, startTmp = 0;
   start = end = 0;
   for( int j = 0; j < size ;  j++ ){  
        thisSum += a[j];
        
        if ( thisSum < 0 )  thisSum = 0;
        else if (thisSum == a[j])    //可能是新的最大子序列
                 startTmp = j;

        if( thisSum > maxSum ){ 
           maxSum = thisSum; start = startTmp; end = j;   
           }
       }

       return maxSum;
  }

算法分析

时间复杂度为O(n)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值