写点什么

LeetCode 题解:53. 最大子序和,动态规划,JavaScript,详细注释

用户头像
Lee Chen
关注
发布于: 2021 年 02 月 20 日
LeetCode题解:53. 最大子序和,动态规划,JavaScript,详细注释

原题链接:https://leetcode-cn.com/problems/maximum-subarray/


解题思路:


  1. 子数组至少包含一个元素,意味着nums[i]必然存在于子数组中。

  2. nums[i]可能与它之前或者之后的元素组成子数组。如果从前往后遍历,子数组元素为nums[i]nums[i + n]的情况,会在遍历到nums[i + n]的时候一起处理。因此遍历时只需要考虑nums[i]与其之前元素的组合情况即可。

  3. 由于nums中的数字有正有负,那么nums[i]之前的子序和有可能为负,此时可以直接抛弃。因此max[i]有两种情况:

* nums[i]包含于之前的子数组中,即为max[i - 1] + nums[i]

* nums[i]不包含于之前的子数组,即为0 + nums[i]

我们只需要在两者间取较大者即可,因此状态转移方程为:max[i] = Math.max(max[i - 1] + nums[i], 0 + nums[i]);

  1. 在每个位置得到的只当前自的最大子序和,最后需要在所有结果中取最大值。


/** * @param {number[]} nums * @return {number} */var maxSubArray = function (nums) {  let max = [nums[0]]; // 递推nums每个值能产生的最大子序和,nums[0]的最大子序和是它自身
// 从1开始递推 for (let i = 1; i < nums.length; i++) { // 子数组至少包含一个元素,因此只需要考虑nums[i]在子数组中的情况 // nums[i]所在的子数组,可能包含它之前和之后的元素。而之后的元素会在后续的遍历中计算,此处无需判断 // 对于nums[i]来说,存在两种情况,它可能包含于之前的子数组,或者从自己开始重新生成一个子数组 max[i] = Math.max( // nums[i]包含于之前的子数组中,上一次的子序和与nums[i]之和为新的子序和 max[i - 1] + nums[i], // nums[i]不包含于之前的子数组,上一次的子序和为0,nums[i]自己就是新的子序和 0 + nums[i] ); }
// 每个位置都会产生一个子序和,最终结果是其中最大者 return Math.max(...max);};
复制代码


  1. 最大值的判断可以在每次遍历时进行,max可以改为变量,存储的是当前已知的最大子序和。

  2. 递推公式中,公共部分nums[i]可以提取出来,减少一次加法计算。由于每个位置的子序和只与上一个位置有关,只需要用一个变量存储。


/** * @param {number[]} nums * @return {number} */var maxSubArray = function (nums) {  let max = nums[0]; // 缓存最大子序和,nums[0]的最大子序和是它自身  let currMax = nums[0]; // 计算当前位置的子序和,初始值即为nums[0]
// 从1开始递推 for (let i = 1; i < nums.length; i++) { // 计算当前位置的子序和 currMax = Math.max( // nums[i]包含于之前的子数组中 currMax, // nums[i]不包含于之前的子数组,上一次的子序和为0 0, ) + // nums[i]必然包含于当前子数组 nums[i]; // 每次对比已知的最大子序和 max = Math.max(max, currMax); }
// 最大子序和已在循环中生成,直接返回即可 return max;};
复制代码


发布于: 2021 年 02 月 20 日阅读数: 10
用户头像

Lee Chen

关注

还未添加个人签名 2018.08.29 加入

还未添加个人简介

评论

发布
暂无评论
LeetCode题解:53. 最大子序和,动态规划,JavaScript,详细注释