题目描述:53. 最大子数组和(中等)
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
LeetCode做题链接:LeetCode-最大子数组和
示例 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 <= nums.length <= 105
-104 <= nums[i] <= 104
进阶: 如果你已经实现复杂度为 O(n)
的解法,尝试使用更为精妙的 分治法 求解。
题目接口
class Solution {
public int maxSubArray(int[] nums) {
}
}
解题思路
本题用到的是动态规划的方法:
定义状态(定义子问题)
dp[i]
:表示以 nums[i]
结尾 的 连续 子数组的最大和。
说明:「结尾」和「连续」是关键字。
状态转移方程(描述子问题之间的联系)
根据状态的定义,由于 nums[i]
一定会被选取,并且以 nums[i]
结尾的连续子数组与以 nums[i - 1]
结尾的连续子数组只相差一个元素 nums[i]
。
假设数组 nums
的值全都严格大于000
,那么一定有 dp[i] = dp[i - 1] + nums[i]
。
可是 dp[i - 1] 有可能是负数,于是分类讨论:
如果 dp[i - 1] > 0
,那么可以把 nums[i]
直接接在 dp[i - 1]
表示的那个数组的后面,得到和更大的连续子数组;
如果 dp[i - 1] <= 0
,那么 nums[i]
加上前面的数 dp[i - 1]
以后值不会变大。于是 dp[i]
「另起炉灶」,此时单独的一个 nums[i]
的值,就是 dp[i]
。
以上两种情况的最大值就是 dp[i]
的值,写出如下状态转移方程:
记为「状态转移方程 1」。
状态转移方程还可以这样写,反正求的是最大值,也不用分类讨论了,就这两种情况,取最大即可,因此还可以写出状态转移方程如下:
记为「状态转移方程 2」。
思考初始值
dp[0]
根据定义,只有 1
个数,一定以 nums[0]
结尾,因此 dp[0] = nums[0]
。
代码
class Solution {
public int maxSubArray(int[] nums) {
int len = nums.length;
// dp[i] 表示:以 nums[i] 结尾的连续子数组的最大和
int[] dp = new int[len];
// 记录以第一个数为结尾的连续子数组的最大和
dp[0] = nums[0];
// 开始进行状态转移方程
for (int i = 1; i < len; i++) {
if (dp[i - 1] > 0) {
dp[i] = dp[i - 1] + nums[i];
} else {
dp[i] = nums[i];
}
}
// 找出dp[i]中的最大值
int res = dp[0];
for (int i = 0; i < len; i++) {
res = Math.max(res, dp[i]);
}
return res;
}
}
成功!
PS:
感谢您的阅读!如果您觉得本篇文章对您有所帮助,请给予博主一个赞喔~
参考题解:经典动态规划问题(理解「无后效性」)