LeetCode系列记录我学习算法的过程。
携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第1天,点击查看活动详情
题目
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6 。
输入: nums = [1]
输出: 1
输入: nums = [5,4,-1,7,8]
输出: 23
提示
1 <= nums.length <= 105-104 <= nums[i] <= 104
进阶: 如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的 分治法 求解。
思路
根据题目及示例,可知给定的数组是一个无序的数组,需在无序数组中找到子项之和最大的连续子数组
这个题目虽然是简单难度,但是看了半天我也没想出什么好的实现方法,只想到暴力法遍历所有情况
但是在写代码理清思路的时候,突然发现一种规律,当遍历到一个新的数组项时,如果与前面记录的子数组和相加
小于当前项时,那前面的和肯定小于 0,需要舍弃,反正则相加,与记录的最大和比较并替换
最后返回记录的最大和即可
代码实现
/**
* @param {number[]} nums
* @return {number}
*/
var maxSubArray = function(nums) {
// max 记录的最大和
// temp 当前子数组和
let max = temp = nums[0]
let i = 1
while(i < nums.length) {
// 如果子数组和加上当前项后大于当前项,则子数组和大于 0,可以保留,记录相加之和
if(temp + nums[i] > nums[i]) {
temp += nums[i]
} else {
// 反正子数组和小于等于 0,舍弃,temp 替换为当前项
temp = nums[i]
}
// 重新判断最大和
max = Math.max(max, temp)
// 移动下标
i++
}
// 返回记录的最大和
return max
};
优化
其他解题思路和我想的都差不多,这种方法属于动态规划,不过有些写法比较简洁:
var maxSubArray = function(nums) {
let sum = 0, max = nums[0]
// 遍历数组
nums.forEach((n) => {
// 子数组和
sum = Math.max(sum + n, n)
// 记录的最大和
max = Math.max(max, sum)
})
return max
};
还有一种方法是分治法,暂时看不懂,先记录下来以后再来研究一下😂
function Status(l, r, m, i) {
this.lSum = l;
this.rSum = r;
this.mSum = m;
this.iSum = i;
}
const pushUp = (l, r) => {
const iSum = l.iSum + r.iSum;
const lSum = Math.max(l.lSum, l.iSum + r.lSum);
const rSum = Math.max(r.rSum, r.iSum + l.rSum);
const mSum = Math.max(Math.max(l.mSum, r.mSum), l.rSum + r.lSum);
return new Status(lSum, rSum, mSum, iSum);
}
const getInfo = (a, l, r) => {
if (l === r) {
return new Status(a[l], a[l], a[l], a[l]);
}
const m = (l + r) >> 1;
const lSub = getInfo(a, l, m);
const rSub = getInfo(a, m + 1, r);
return pushUp(lSub, rSub);
}
var maxSubArray = function(nums) {
return getInfo(nums, 0, nums.length - 1).mSum;
};