最大子序列和问题

最大子序列和问题解析
本文解析了最大子序列和问题,并提供了一种O(n)的动态规划解决方案。通过定义b[j]为到下标j为止连续子序列的最大和,利用状态转移方程b[j]=max{b[j-1]+a[j],a[j]}

问题描述:给定一整数序列A1, A2,... An (可能有负数),求A1~An的一个子序列Ai~Aj,使得Ai到Aj的和最大 

这是我前几天参加新浪广告算法组面试的时候一个题目。自己当时脑袋浆糊了,加上前面答的不好,这里答的时候脑子一片空白。哎~

这一题本质在于动态规划的运用。至于O(n^3), O(n^2),还有O(nlogn)的解法我就不多说了。

先上代码

int FindMaxSumSubSequence(int a[], int len)
{
     int max  = 0;
     int sum = 0;
     for(int i = 0; i < len; i++)
     {
           sum += a[i];
           if ( sum > max )
                max = sum;
           else if ( sum < 0)
               sum = 0;
      }
      return max;
}

关键在于如何理解这样一段代码。

网上大众的解释如下

“在这一遍扫描数组当中,从左到右记录当前子序列的和temp_sum,若这个和不断增加,那么最大子序列的和max也不断增加(不断更新max)。如果往前扫描中遇到负数,那么当前子序列的和将会减小。此时temp_sum 将会小于max,当然max也就不更新。如果temp_sum降到0时,说明前面已经扫描的那一段就可以抛弃了,这时将temp_sum置为0。然后,temp_sum将从后面开始将这个子段进行分析,若有比当前max大的子段,继续更新max。这样一趟扫描结果也就出来了。” 

这是一种比较通俗化的描述,但没有深入动态规划的本质解释。尤其是如何解释“说明前面已经扫描的那一段就可以抛弃了”这样一句话。

下面将从动态规划的角度解释为什么可以在O(n)复杂度内解决问题

根据定义,我们可以定义bj

那么最大子段和为

由bj的定义知,b[j-1] > 0 时, b[j] = b[j-1] + a[j],否则b[j] = a[j]

故状态转移方程为b[j] = max{b[j-1]+a[j], a[j]}

故代码如下

int MaxSum(int a[], int len)
{
     int sum = 0;
     int b = 0;
     for(int i = 0; i < n; ++i)
     {
          if ( b>0 ) 
               b+=a[i];
          else
               b = a[i];
          
          if ( b > sum ) sum = b;
     }
     return sum;
}

写到这里 ,还需要解释几个比较让人迷惑的问题

1) b[j]到底是个什么东西?

b[j]本质上就是到下标为j的地方为止,连续子序列的最大和。

那么整个数组的最大子序列和就是max(b[i])

2) b[j]具有最优子结构么

当然,任意一个b[j]均由b[j-1]扩展而来,为什么,请结合问题1)。扩展的方式如上文所述。故可以用状态转移方程统一描述。

3) 为什么b[j-1] > 0  b[j] = b[j-1] + a[j],否则b[j] = a[j]

 看图,如果是负数,那么在此基础上扩展,和一定会变小,与其如此,不如选定新的和,即b[j] = a[j]

转载于:https://www.cnblogs.com/ShaneZhang/p/3768773.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值