携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第24天,点击查看活动详情
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),空间复杂度O(1)
// 第二种
思路:不断分割,直到每个部分是一个数字为止,然后不断合并,返回左右和左右合并之后,3个最大子序和中的最大的一个
复杂度:时间复杂度O(nlogn),二分复杂度O(logn),二分之后每一层统计左右和合并之后的最大子序和复杂度是O(n),所以之后的复杂度是O(nlogn)。空间复杂度O(logn),递归的栈空间,因为是二分,每次数据规模减半
代码实现
// 第一种
var maxSubArray = function(nums) {
const dp = [];
let res = (dp[0] = nums[0]);//初始化状态
for (let i = 1; i < nums.length; ++i) {
dp[i] = nums[i];
if (dp[i - 1] > 0) {//前面的状态是正数 则加上
dp[i] += dp[i - 1];
}
res = Math.max(res, dp[i]);//更新最大值
}
return res;
};
//状态压缩
var maxSubArray = function(nums) {
let pre = 0, maxAns = nums[0];
nums.forEach((x) => {
pre = Math.max(pre + x, x);
maxAns = Math.max(maxAns, pre);
});
return maxAns;
};
// 第二种
function crossSum(nums, left, right, mid) {
if (left === right) {//左右相等 返回左边的值
return nums[left];
}
let leftMaxSum = Number.MIN_SAFE_INTEGER;//左边最大值初始化
let leftSum = 0;
for (let i = mid; i >= left; --i) {
leftSum += nums[i];
leftMaxSum = Math.max(leftMaxSum, leftSum);//更新左边最大子序和
}
let rightMaxSum = Number.MIN_SAFE_INTEGER;
let rightSum = 0;
for (let i = mid + 1; i <= right; ++i) {
rightSum += nums[i];
rightMaxSum = Math.max(rightMaxSum, rightSum);//更新右边最大子序和
}
return leftMaxSum + rightMaxSum;//返回左右合并之后的最大子序和
}
function _maxSubArray(nums, left, right) {
if (left === right) {//递归终止条件
return nums[left];
}
const mid = Math.floor((left + right) / 2);
const lsum = _maxSubArray(nums, left, mid);//左边最大子序和
const rsum = _maxSubArray(nums, mid + 1, right);//右边最大子序和
const cross = crossSum(nums, left, right, mid);//合并左右的之后的最大子序和
return Math.max(lsum, rsum, cross);//返回3中子序和中最大的
}
var maxSubArray = function(nums) {
return _maxSubArray(nums, 0, nums.length - 1);
};
如果你对这道题目还有疑问的话,可以在评论区进行留言;
\