LeetCode0053.最大子数组和 Go语言AC笔记

时间复杂度:O(n)

解题思路

非常经典的动态规划题目!

-2 11 -4 13 -5 -2为例:

步骤1:令状态dp[i]表示以nums[i]作为末尾的连续序列的最大和(这里是说nums[i]必须作为连续序列的末尾)。以样例为例:序列-2 11 -4 13 -5 -2,下标分别记为0,1,2,3,4,5,那么

  • dp[0]=-2
  • dp[1]=11
  • dp[2]=7 (11-4=7)
  • dp[3]=20 (11-4+13=20)
  • dp[4]=15 (因为由dp数组的含义,nums[4]=-5必须作为连续序列的结尾,于是最大和就是11-4+13-5=15,而不是dp[3]的20)
  • dp[5]=13 (11-4+13-5-2=13)

通过设置这么一个dp数组,要求的最大和其实就是dp[0],dp[1],...,dp[n-1]中的最大值(因为到底以哪个元素结尾未知),下面想办法求解dp数组。

步骤2:作如下考虑:因为dp[i]要求是必须以nums[i]结尾的连续序列,那么只有两种情况:

  1. 这个最大和的连续序列只有一个元素,即以nums[i]开始,以nums[i]结尾
  2. 这个最大和的连续序列有多个元素,即从前面某处nums[p]开始(p<i),一直到nums[i]结尾

对第一种情况,最大和就是nums[i]本身。

对第二种情况,最大和是dp[i-1]+nums[i],即nums[p]+...+nums[i-1]+nums[i]=dp[i-1]+nums[i]。

由于只有这两种情况,于是得到状态转移方程:

dp[i]=max{nums[i],dp[i-1]+nums[i]}

这个式子只和i与i前一个元素有关,且边界为dp[0]=nums[0],由此从小到大枚举i,即可得到整个dp数组。接着输出dp[0],dp[1],...,dp[n-1]中的最大值即为最大连续子序列的和。

这样只用O(n)的时间复杂度就解决了原先需要O(n²)复杂度问题,这就是动态规划的魅力!

通过观察我们发现,dp[i]只与dp[i-1]有关,故可以利用滚动数组的思想只用一个变量代替dp的一维数组。

 AC代码

func maxSubArray(nums []int) int {
    res:=nums[0]
    for i:=1;i<len(nums);i++{
        if nums[i-1]+nums[i]>nums[i]{
            nums[i]+=nums[i-1]
        }
        if nums[i]>res{
            res=nums[i]
        }
    }
    return res
}

感悟

作为极为经典的动态规划题目,一定要熟练写出AC代码,特别要理解dp的含义,以及状态转移方程,这样才能更好地理解动态规划。

对于最大连续子序列和的题目,设计的动态规划模型为:

令dp[i]表示以nums[i]作为末尾的连续序列的最大和

此题目又可以用滚动数组的思想用一个变量代替dp数组,将空间复杂度从O(n)降到O(1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

SwithunH

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

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

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

打赏作者

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

抵扣说明:

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

余额充值