• 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    贪心:

    贪心贪的是总和大于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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    科普长文--网络安全拟态防御技术概念及应用
    java计算机毕业设计基于安卓Android/微信小程序的小区智能超市购物商城APP
    UI自动化测试 | Jenkins配置优化
    ESP32 MicroPython 蜂鸣器及传感器的使用⑦
    go 端口转发 代理 --chatGPT
    安装ora2pg遇到如下问题
    【Hack The Box】windows练习-- Bounty
    ImmunoChemistry艾美捷绿色活/死染色解决方案
    【基于Qt和OpenCV的多线程图像识别应用】
    mac免费杀毒软件哪个好用?如何清理mac系统需要垃圾
  • 原文地址:https://blog.csdn.net/qq_38737428/article/details/127716355