LeetCode 53. 最大子序和

111 阅读2分钟

image.png

解析

解法1 (贪心算法)

  • 局部最优:当前“连续和”为负数的时候立刻放弃,从下一个元素重新计算“连续和”,因为负数加上下一个元素 “连续和”只会越来越小。
  • 全局最优:选取最大“连续和”
  • 局部最优的情况下,并记录最大的“连续和”,可以推出全局最优。
/**
 * @param {number[]} nums
 * @return {number}
 */
 // 时间复杂度:O(n)
var maxSubArray = function(nums) {
    let len = nums.length
    let sum = 0
    let result = 0
    if(len <= 1){
        return nums
    }
    for(let i = 0;i<len;i++){
        // 如果 sum > 0,则说明 sum 对结果有增益效果,则 sum 保留并加上当前遍历数字
        if(sum > 0){
            sum  = sum + nums[i]
        //否则的话之前是负数,加了只会更小,不如从新的开始
        }else {
            sum = nums[i]
        }
        //每次比较 sum 和 result的大小,将最大值置为result,遍历结束返回结果
        result = Math.max(result,sum)
    }
    return result
};

解法2 (动态规划)

    1. 确定dp数组(dp table)以及下标的含义
    • dp[i]:包括下标i之前的最大连续子序列和为dp[i]
    1. 确定递推公式
    • dp[i]只有两个方向可以推出来:
      • dp[i - 1] + nums[i],即:nums[i]加入当前连续子序列和
      • nums[i],即:从头开始计算当前连续子序列和'
      • 一定是取最大的,所以dp[i] = max(dp[i - 1] + nums[i], nums[i]);
    1. dp数组如何初始化
    • dp[0]就是递推公式的基础。
    • dp[0]因为为nums[0]dp[0] = nums[0]
    1. 确定遍历顺序
    • 递推公式中dp[i]依赖于dp[i - 1]的状态,需要从前向后遍历。
    1. 推导dp数组
/**
 * @param {number[]} nums
 * @return {number}
 */
 // 时间复杂度:O(n)
var maxSubArray = function(nums) {
    let len = nums.length
    let dp = [nums[0]]
    let max = dp[0];
    for(let i = 1; i < len; i++){
        dp[i] = Math.max(dp[i-1]+nums[i],nums[i])
        max = Math.max(max, dp[i])
    }
    return max
};

解法3 (暴力求解)