最大子数组和-LeetCode
53. 最大子数组和-LeetCode
🎯 问题描述(来源于LeetCode)
描述:给你一个整数数组 nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
说明:
-
子数组是数组中的一个连续部分。
-
示例:
- 示例 1:
1
2
3输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6。- 示例 2:
1
2输入:nums = [1]
输出:1
💻 解题思路
思路1:动态规划 (Kadane算法)
核心思想:
这道题的关键在于**“局部最优”导致“全局最优”。
我们不需要关心整个数组怎么切分,只需要关注:“如果我要以当前位置 i 结尾,我能得到的最大和是多少?”**
- 状态定义:
dp[i]表示以nums[i]结尾的连续子数组的最大和。 - 贪心策略(状态转移):
- 当我们走到
nums[i]时,我们面临两个选择:- 加入前面的队伍:如果前面的
dp[i-1]是正数(有利可图),那就加上它。 - 另起炉灶:如果前面的
dp[i-1]是负数(它是累赘),那不如抛弃它,从nums[i]重新开始。
- 加入前面的队伍:如果前面的
- 公式:
dp[i] = max(nums[i], dp[i-1] + nums[i])。
- 当我们走到
- 结果:
dp数组中的最大值即为答案(因为最大子数组不一定以最后一个元素结尾)。
算法步骤:
- 初始化
dp数组,dp[0] = nums[0]。 - 从
i = 1开始遍历数组。 - 根据
dp[i-1]的正负性更新dp[i]。 - 遍历
dp数组,返回最大值。
思路1:代码实现
1 | class Solution: |
思路1:📊 性能分析
提交结果
- 运行时间:47 ms (击败 64.43%)
- 内存消耗:31.02 MB (击败 31.62%)
复杂度验证
-
- 解析:只需要遍历一次数组。
-
- 解析:使用了一个长度为
n的dp数组。- 优化提示:其实我们只需要
dp[i-1],不需要保存整个数组,可以用一个变量pre_max代替,将空间复杂度降为 。
- 优化提示:其实我们只需要
- 解析:使用了一个长度为
思考
-
为什么是
dp[i-1] < 0而不是nums[i-1] < 0?- 这是一个常见的误区。我们要判断的是**“前面那一串子数组的总和”**是不是累赘,而不是判断前一个数字是不是负数。
- 例如:
[10, -5, 2]。虽然-5是负数,但10 + (-5) = 5是正数。对于2来说,前面的总和5是有帮助的,所以应该接上去。你的代码逻辑dp[i-1] < 0完美处理了这种情况。
-
如何优化空间复杂度到 ?
- 既然
dp[i]只依赖dp[i-1],我们完全可以用一个变量current_max来滚动记录,不需要开数组。 - 这也是这道题的最佳解法(Kadane算法的标准版):
- 既然
1 | class Solution: |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 笺札!






