算法TS-最大子数组和

62 阅读2分钟

leetcode53

给你一个整数数组 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(N),空间复杂度也是 O(N)

var maxSubArray = function(nums) {
    let len = nums.length;
    if(!len)return 0;
    let dp = Array(len);
    // dp[i]的定义:nums数组切开,以nums[i]这个元素结尾的子数组,最大连续子数组和
    // 想象一下,你知道一个数组的最大连续子数组和为S1,那么如果再让数组里添加一个元素M,那最大的子数组和的值可能是S1+M 或者M(不可能是S1因为结尾的元素必须是nums[i]),
    dp[0] = nums[0];
    let max = Number.MIN_SAFE_INTEGER;
    for(let i = 1; i< len; i++) {
        dp[i] = Math.max(nums[i], dp[i-1] + nums[i])
    }
    for(let i = 0;i < len;i++) {
        max = Math.max(max, dp[i])
    }
    return max;
}

方法二: 分治求解,时间复杂度o(N),空间复杂度o(1)

观察发现,dp[i]的值只跟dp[i-1]有关,那么可以使用滚动更新的方式,可以降低空间复杂度

var maxSubArray = function(nums) {
    let len = nums.length;
    if(!len) return 0;
    let dp_i_1 = nums[0], dp_i_2, max = Number.MIN_SAFE_INTEGER
    for(let i = 1; i < len; i++) {
        //滚动更新
        dp_i_2 = Math.max(dp_i_1 + nums[i], nums[i])//根据dp_i_1计算出dp_i_2
        dp_i_1 = dp_i_2 // 把dp2赋值给dp1,往后挪一步
        max = Math.max(dp_i_2, max)// 重新计算max
    }
    return max;
}