这是我参与2022首次更文挑战的第26天,活动详情查看:2022首次更文挑战
题目
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
思路
-
常规做法我们可以采用双重
for
循环枚举每一种可能性,然后维护一个前缀和二维数组的空间,用来记录从i
到j
中的元素累加的和是多少; -
然而实际上我们在解决这些最大和的时候,大部分题目可以采用贪心来做,所谓的贪心,就是尽可能维持你前面部分的和越大越好;
-
举个例子,如果前面的第一个元素是
3
, 我们累加起来, 第二个元素是-2
,这时候我们加不加呢?答案是肯定的,因为3 - 2 > 0
, 只要前面是大于0
的部分我们就累加起来,小于0
的部分我们就舍去从头开始,然后最终判断每一次累加后的值
,取其中的最大值
作为我们的答案;如:
[3, -2, 3]
这个数组:- 初始值: 前缀prev为0, 最大值result为最小的数字 - 第一轮的时候: 前缀累加变成3, 最大值取原本的值和当前前缀的最大值为3 - 第二轮的时候: 前缀累加变成1, 最大值取原本的值和当前前缀的最大值为3 - 第三轮的时候: 前缀累加变成4, 最大值取原本的值和当前前缀的最大值为4
很多小伙伴在遇到
-2
的时候就会想着从0
开始从新计算了,这是这道题目比较容易陷入的一个误区。 -
这样子只需要经过一轮遍历我们就可以找到我们要的答案,同时空间复杂度为O(1)。
实现
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
// 记录前缀
let prev = 0;
// 记录最大值结果
let result = Number.MIN_SAFE_INTEGER;
// 一轮循环,枚举结果
for (let i = 0; i < nums.length; i++) {
// 当前最大前缀加当前值和我们上一轮的最大值比较
result = Math.max(result, nums[i] + prev);
// 前缀保证是正值,如果是负值就舍去
prev = Math.max(prev + nums[i], 0);
}
return result;
};
看懂了的小伙伴可以点个关注、咱们下道题目见。如无意外以后文章都会以这种形式,有好的建议欢迎评论区留言。