leetcode-最大子序和

题目描述:
  给定一个整数数组 n u m s nums nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:
  输入: [ − 2 , 1 , − 3 , 4 , − 1 , 2 , 1 , − 5 , 4 ] [-2,1,-3,4,-1,2,1,-5,4] [2,1,3,4,1,2,1,5,4],
  输出: 6 6 6
  解释: 连续子数组 [ 4 , − 1 , 2 , 1 ] [4,-1,2,1] [4,1,2,1] 的和最大,为 6 6 6

  这一题leetcode上并没有详细的分析,看别人的讲解也说的不是特别的详细,这里我按照自己的理解方式做一个分析。

  首先这一题可以用动态规划算法,但是递推关系式的推出,是十分复杂的,其难度不应该是easy(当然仅从代码量角度看,确实是easy)。其python3实现代码如下

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        for i in range(1, len(nums)):
            nums[i] = nums[i] + max(nums[i-1], 0)  
        return max(nums)

从代码可以看出递推关系式是 C [ i ] = C [ i ] + m a x ( C [ i − 1 ] , 0 ) C[i] = C[i] + max(C[i-1], 0) C[i]=C[i]+max(C[i1],0)下面主要讲述这个递推关系式是怎么推出来的,主要用的扫描法,扫描法简单理解,就是上面的递推关系式,从 i = 0 i=0 i=0,递推(扫描)到 i = n − 1 i=n-1 i=n1( n n n n u m s nums nums的长度),得到所有的 C [ i ] C[i] C[i]。通过扫描法,我们其实只考虑了 n n n个子序列,但是根据排列组合,有 1 + 2 + 3 + ⋯ + n = O ( n 2 ) 1+2+3+\dots +n = O(n^{2}) 1+2+3++n=O(n2)个子序列,因为长度为 n n n的子序列只有 1 1 1个,长度为 n − 1 n-1 n1的子序列有 2 2 2个,长度为 n − 2 n-2 n2的子序列有 3 3 3个,长度为 4 4 4……。我们证明的主要思路是, O ( n 2 ) O(n^{2}) O(n2)中的其余子序列情况的子序和一定小与等于扫描法考虑的n个子序列情况的子序和,因此才遗弃它们的。最后我们在 n n n个子序列中选出最大的即可。

  首先说明一下 C [ i ] C[i] C[i]的含义,其表示 n u m s [ 0 ] nums[0] nums[0]扫描到 n u m s [ i ] nums[i] nums[i],得到的包含 n u m s [ i ] nums[i] nums[i]的最大自序和,从两个子场景说明:

场景一:递推执行到索引 m m m,未出现 C [ i ] < 0 ( i = 0 , 1 , 2 , … m − 1 ) C[i]<0(i=0,1,2,\dots m-1) C[i]<0(i=0,1,2,m1)的情况,这样我们的递推式其实变成 C [ i ] = ∑ j = 1 i n u m s [ j ] C[i]= \sum\limits_{j=1}^{i}nums[j] C[i]=j=1inums[j],这样我们仅考虑了 m m m个子序的和,分别是 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 2 2 2…… 0 0 0 m − 1 m-1 m1 m m m个子序,子序开头全是 0 0 0,我们没有考虑的子序有两种情况,

  情况一:以 m m m结尾,开头任意的子序,其示意图如下:

   b b b代表情况一没有考虑到的任意一个子序的子序和,我们有
a > 0 , c > 0 a>0,c>0 a>0,c>0这是场景一的假设,又 a + b = c b = c − a a+b=c\\b=c-a a+b=cb=ca所以 b < c b<c b<c,所以情况一所考虑的子序和 b b b,全部没有对应的场景一考虑的子序和 c c c大,所以被遗弃。

  情况二:开头结尾都任意的子序。其示意图如下:

   b b b代表情况二没有考虑到的任意一个子序的子序和,我们有
a > 0 , d > 0 a>0,d>0 a>0,d>0这是场景一的假设,又 a + b = d b = d − a a+b=d\\b=d-a a+b=db=da所以 b < d b<d b<d,所以情况二所考虑的子序和 b b b,全部没有对应的场景一考虑的子序和 d d d大,所以被遗弃。至于 d 、 c d、c dc谁更大,我们需要单独讨论。

场景二:递推执行到索引 m m m,第一次出现 C [ m − 1 ] < 0 C[m-1]<0 C[m1]<0,言外之意 C [ i ] ≥ 0 ( i = 0 , 1 , 2 , … m − 2 ) C[i]\geq 0(i=0,1,2,\dots m-2) C[i]0(i=0,1,2,m2),这样我们的递推式还是 C [ i ] = ∑ j = 1 i n u m s [ j ] ( i = 0 , 1 , 2 , … m − 1 ) C[i]= \sum\limits_{j=1}^{i}nums[j](i=0,1,2,\dots m-1) C[i]=j=1inums[j](i=0,1,2,m1),但是 i > m − 1 i>m-1 i>m1就要截断 n u m s nums nums,即从 m m m开始重新计算子序,有一种把索引 m m m当成索引 0 0 0的感觉,这是正常思维,如果不舍弃前面,加个负数的子序和一定小于舍弃前面的情况。但这样我们没有考虑的子序也有两种情况,

  情况三:以 m m m结尾,开头任意的子序,其示意图如下(和情况一长得一样,但是 c < 0 c<0 c<0)

   b b b代表情况三没有考虑到的任意一个子序的子序和,我们有
a > 0 , c < 0 a>0,c<0 a>0,c<0这是场景二的假设,又 a + b = c b = c − a < 0 a+b=c\\b=c-a<0 a+b=cb=ca<0所以 b < a b<a b<a,所以情况三所考虑的子序和 b b b,全部没有对应的子序和 a a a大,所以被遗弃。

  情况四:跨过 m m m的子序。其示意图如下:

   e e e代表情况四没有考虑到的任意一个子序的子序和,我们有
b < 0 b<0 b<0这是情况三的推论,又 b + d = e b+d=e b+d=e所以 e < d e<d e<d,所以情况四所考虑的子序和 e e e,全部没有从 m m m开始重新考虑子序的子序和 d d d大,所以被遗弃。

  接下来,我们就不断重复迭代场景一,场景二,就遗弃了其余的 O ( n 2 ) − n O(n^{2})-n O(n2)n个子序,所以想推出上面的递推关系式,其分析是比较复杂的。


参考:
https://blog.csdn.net/zwzsdy/article/details/80029796

从一道easy leetcode问题,谈谈最大子列和的Kadane算法(强烈推荐):https://blog.csdn.net/the__apollo/article/details/77367534

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值