最大子序和
LeetCode 53 力扣 53. 最大子序和
思路
nums[0] 记录当前子串和;遍历按个加元素,如果加之后maxSum更大就更新其数值;
遍历:
- 如果
sum <= 0,那么后面的子序列肯定不包含目前的子序列,所以令sum = num - 如果
sum > 0,加上当前元素能使后面的子序列和更大,所以sum += num
let maxSum = 0;
let sum = nums[0]; // 记录当前和
// 按个加,如果加之后maxSum更大就更新
for (var num in nums){
if (sum <= 0){
// 如果sum<=0,那么后面的子序列肯定不包含目前的子序列,所以令sum = num
sum = num;
} else {
// 如果sum > 0,加上当前元素能使后面的子序列和更大
sum += num;
}
maxSum = Math.max(maxSum, sum)
}
return maxSum;

- 执行用时:92 ms, 在所有 JavaScript 提交中击败了58.27%的用户
- 内存消耗:39.5 MB, 在所有 JavaScript 提交中击败了22.66%的用户
Kadane算法和代码优化
- 可以用于求maximum value of a subarray,最大子串和、最大子串积等等;
- 也就是上面代码里的分割子串思路:遍历数组时把可能遇到的子串元素分成两类,一类拥有和为正数的前缀子串(前面连着的几个元素),另一类的前缀子串和为负;
- 因为我们需要取得连续的子串,所以对于后一类来说,我们可以直接将当前元素作为待选最大子串和子串的开头,继续遍历;
- 如果前缀子串和大于零,此前缀子串很有可能就是我们想要的结果,所以可以保留,直接把当前元素加到这个子串里就好。
更标准的算法解释
(Reference From: 求和最大子串(Kadane算法) 算法简明推理 - 代码天地)
- 目标:前缀子串和与后缀子串和均大于0
-
我们分割原数组成若干子串。切割方式:
- 子串和小于0(除了最后一个子串之外)
- 子串的前缀子串和大于0
-
由1,2我们推得
- 子串的后缀子串和小于0
-
由1,3推得
- 目标是某一子串的子串(即目标不可能跨越多个子串)
-
然后由2,4推得
-
目标是某子串的前缀子串
-
最终,我们在分割子串的过程中就能把目标的和(或者是目标)求出来。
代码优化
var maxSubArray = function(nums) {
let maxSum = nums[0];
let sum = 0; // 记录当前和
// 按个加,如果加之后maxSum更大就更新
for (const num of nums){
sum = Math.max(num + sum, num);
maxSum = Math.max(maxSum, sum);
}
return maxSum;
};

- 执行用时:80 ms, 在所有 JavaScript 提交中击败了94.45%的用户
- 内存消耗:39 MB, 在所有 JavaScript 提交中击败了95.11%的用户
- 心得:不知不觉就学会了一种名字听起来很高级的算法(还是CMU教授设计的) 😀
易错点
⚠️sum = Math.max(num + sum, num)而不是sum = Math.max(num + sum, sum)!是将前缀子串和+当前元素值与 (不加前缀子串和的)当前元素值 进行比较,从而分离两类子串。

本文介绍了LeetCode 53题的最大子序和问题,通过Kadane算法来求解,并提供了JavaScript实现。文章详细解释了算法思路,包括如何将数组元素分为两类以及算法的标准解释,同时分享了代码优化后的性能提升,帮助读者深入理解并掌握该算法。

382

被折叠的 条评论
为什么被折叠?



