最大子序列和

问题描述

        给定(可能是负的)整数序列A1, A2,...,AN, 寻找(并标识)使Sum(Ak)(k >=i, k <= j)的值最大的序列。如果所有的整数都是负的,那么连续子序列的最大和是零。例如:输入整数序列: -2, 11, 8, -4, -1, 16, 5, 0,则输出答案为35,即从A2~A6。


O(n)解法:

def max_subseq_sum(seq):
    '''
    :type seq: []
    :rtype: int
    '''
    MaxSum = 0
    ThisSum = 0
    for i in range(len(seq)):
        ThisSum += i
        if ThisSum > MaxSum:
            MaxSum = ThisSum
        else:
            if ThisSum < 0:
                ThisSum = 0
    return MaxSum



我们在数组中间找到的连续子序列,可能存在和为负的序列。如果需要找到一个最大的子数组的话,肯定该序列不是在最大子序列当中的。我们可以通过反证的方式来证明。

    假设数组A[i...j],里面的元素和为负。如果A[i....j]在一个最大子序列的数组中间,假定为A[i...k],k > j。那么既然从i到j这一段是负的,我把这一段去掉剩下的部分完全比我们假定的这个最大子序列还要大。这就和我的假设矛盾了。

    这个假设还有一个限制,就是该数组就是从i开头的。否则有人可能会这么问,如果我A[i...j]这一部分确实是一个负数,但是在A[i]前面是一个很大的正数,使得他们的和为正数。那不就使得我们的结果不成立了么?如果我们是从某个数组的开头i开始的话,就不存在这个情况。

        结合前面的讨论,我们就可以发现一个有意思的事情,就是假设我们从数组的开头A[0]开始,不断的往后面走,每一步判断是否当前和最大,并保存结果。当发现当前字串和为负数的时候,我们可以直接跳过。假设当前的索引为i的话,从0到i这一段的和是负数,可以排除。然后再从当前元素的后面开始找。这样可以得到最终最大子串和以及串的起点和终点。


如果a[i]是负数,那么它不可能代表最优序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过使用a[i+1]作为起点得到改进。类似的,任何负的子序列也不可能是最优子序列的前缀(原理相同)。如果在内循环中检测到从a[i]到a[j]的子序列的和是负数,那么可以向后推进i。关键的结论是:我们不仅能够把i推进到 i+1,而且实际上我们还可以把它一直推进到 j+1。为了看清楚这一点,我们令 p 为 i+1 和 j 之间的任意一下标。开始于下标 p 的任意子序列都不大于在下标i开始并包含从 a[i] 到 a[p-1] 的子序列的对应的子序列,因为后面这个子序列不是负的(即j是使得从下标 i 开始,其值成为负值的序列的第一个下标)。因此,把 i 推进到 j+1 是没有风险的:我们一个最优解也不会错过。

 

参考:

http://shmilyaw-hotmail-com.iteye.com/blog/1616632

http://m.oschina.net/blog/267860

转载于:https://my.oschina.net/sukai/blog/656407

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值