【LeetCode】每日一题 最大子数组和

72 阅读1分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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);
};

如果你对这道题目还有疑问的话,可以在评论区进行留言;

\