leetcode(力扣) 53. 最大子数组和 (动态规划 & 贪心)

题目描述

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。

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

示例 2:
输入:nums = [1]
输出:1

示例 3:
输入:nums = [5,4,-1,7,8]
输出:23

动态规划

思路分析

老规矩,动态规划五步走:

1.确定dp下标含义:

dp[i] 定义为以下标i为结束下标的子数组的最大和。

这里要注意:只是以i为结束下标,并不一定是以0为开始的。只要记住这里可能是0 到 i , 1 到 i , n到i,反正就是 不管是从哪里到i,dp[i] 就表示到下标i的子序列的最大和。

2.状态转移公式:

遍历到nums[i] 的时候,肯定是要这个值,因为我们dp的含义就是到这个值的,也就是从这个值之前的子数组的最大和。

在必须选择nums[i]的情况下:

  • dp[i-1] 是大于0的,那么这时候直接把nums[i] 加入就行
  • dp[i-1] 是小于等于0的,那么这时候就不要前面那些了,直接另起炉灶 dp[i-1] = nums[i]即可。

这块一个疑问,对于第一个情况,dp[i-1]是大于0的,如果即将加入的nums[i] 小于0,那为啥还要加入,不加他岂不是更大?
这块就要回头看dp的含义了,dp表示以i下标为结尾的,也就是以nums[i]为结尾的最大子数组和,所以当前的nums[i]无论如何必加入。

归根结底是因为这道题要求的是子数组,而不是子序列,子数组要求连续,不能中间扔掉某个值,所以才有了这样的dp定义,以及这样的状态转移公式。

3.初始化dp

如果所给数组只有一个值,那么她的最大子数组肯定是他本身,所以这里dp[0] = nums[0]。

其他值是什么都无所谓了,因为是根据前面和nums推出来的,会覆盖掉。

4.遍历顺序

看dp定义,后一个依赖于前一个,所以从前到后正向遍历没毛病。

这里有一个东西就是返回什么值,要看dp的含义,再来一遍,dp[i] 定义为以下标i为结束下标的子数组的最大和。
如果直接返回dp[-1],那就是以最后一个值为结尾的最大子数组和,显然不对。
所以要找个变量res记录遍历过程中dp[i]的最大值,或者返回的时候直接是max(dp)

记录答案的这个变量res初始化要让他等于所给数组nums的第一个值,预防nums长度等于1的情况。

完整代码

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # dp[i] 定义为以下标i为结束下标的子数组的最大和

        dp = [0] * len(nums)
        dp[0] = nums[0]
        res = nums[0]
        for i in  range(1,len(nums)):
            dp[i] = max(dp[i-1]+nums[i],nums[i])
            res = max(res,dp[i])

        print(res)
        return res

贪心:

贪心贪的是总和大于0,只要总和小于0,则不要他们了,另起炉灶。

比如 -2 1 在一起,计算起点的时候,一定是从1开始计算,因为负数只会拉低总和,这就是贪心贪的地方!

思路:
遍历nums,从头开始用count累积,如果count一旦加上nums[i]变为负数,那么就应该从nums[i+1]开始从0累积count了,因为已经变为负数的count,只会拖累总和。
在这期间别而忘了记录count的最大值。也就是说,count变为复数之前是记录过总和的了。

举例:

对于示例1: nums = [-2,1,-3,4,-1,2,1,-5,4]

  • count 计数器初始化为0,res = -99999999。
  • 扫描到-2 时, count = -2 ,记录此时count和res的最大值,即res = -2。
  • 判断count是否小于0,若小于0则不要前面的东西了,count另起炉灶,count=0。
  • 扫描到1 时, count = 1 ,记录此时count和res的最大值,即res = 1。
  • 判断count是否小于0,count =1 不小于0。
  • 扫描到-3 时, count = 1-3 = -2 ,记录此时count和res的最大值,即res = 1。
  • 判断count是否小于0,count = -2 ,count另起炉灶,count=0。
  • 扫描到4 时, count = 0+4=4 ,记录此时count和res的最大值,即res = 4。



写不动了,
以此类推。

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:

        result = -float('inf')
        count = 0
        for i in range(len(nums)):
            count += nums[i]
            result = max(result,count)
            if count <= 0:
                count = 0
        return result
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

深度不学习!!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值