题目链接: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 <= nums.length <= 105
-104 <= nums[i] <= 104
进阶:如果你已经实现复杂度为 O(n)
的解法,尝试使用更为精妙的 分治法 求解。
文章讲解:代码随想录
视频讲解:看起来复杂,其实是简单动态规划 | LeetCode:53.最大子序和_哔哩哔哩_bilibili
题解1:贪心算法
思路:之前已经用贪心算法做过此题,再来回顾一下。遍历数组然后求和,局部最优为每一步都取正数和,舍弃负数和,全局最优为得到最大子数组和。
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let res = nums[0];
let sum = 0;
for (let i = 0; i < nums.length; i++) {
sum += nums[i];
res = Math.max(res, sum);
if (sum < 0) {
sum = 0;
continue;
}
}
return res;
};
分析:时间复杂度为 O(),空间复杂度为 O()。
题解2:动态规划
思路:以 nums[i] 结尾的最大子数组和与 nums[i - 1] 结尾的最大子数组和相关,可以使用动态规划法求解。
动态规划分析:
- dp 数组以及下标的含义:dp[i] 代表以 nums[i] 结尾的最大子数组和。
- 递推公式:dp[i] = dp[i - 1] > 0 ? dp[i - 1] + nums[i] : nums[i]。
- dp 数组初始化:dp[0] = nums[0]。
- 遍历顺序:从前到后。
- 打印 dp 数组:以输入 [-2,1,-3,4,-1,2,1,-5,4] 为例,dp 数组为 [ -2, 1, -2, 4, 3, 5, 6, 1, 5 ]。
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
let res = nums[0];
const dp = new Array(nums.length).fill(0);
dp[0] = nums[0];
for (let i = 1; i < nums.length; i++) {
dp[i] = dp[i - 1] > 0 ? dp[i - 1] + nums[i] : nums[i];
res = Math.max(res, dp[i]);
}
return res;
};
分析:时间复杂度为 O(n),空间复杂度为 O(n)。
可以看出 dp[i] 只依赖于 dp[i - 1],可以考虑状态压缩。实际上,状态压缩后的代码就是贪心思路的代码。
收获
练习使用动态规划法求解子序列问题,子序列包括子数组,子数组是连续的,子序列可以是不连续的。