LeetCode 53 Maximum Subarray (Tag:Array Difficulty:Easy)

171 阅读3分钟

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

前言

关于 LeetCode 数组类型题目的相关解法,可见LeetCode 数组类型题目做前必看,分类别解法总结了题目,可以用来单项提高。觉得有帮助的话,记得多多点赞关注哦,感谢!

题目描述

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例 1:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

示例 2:
输入:nums = [1]
输出:1

示例 3:
输入:nums = [0]
输出:0

示例 4:
输入:nums = [-1]
输出:-1

示例 5:
输入:nums = [-100000]
输出:-100000

链接:leetcode-cn.com/problems/ma…

题解

  1. 暴力搜索. 暴力搜索很好理解, 题目要求找到连续子数组的最大和, 那么我们可以从数组第一个元素起, 依次找出所有的相邻子数组, 求和并将最大的和保存下来. 具体见代码.

    时间复杂度 O(n²), 空间复杂度 O(n).

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    // 初始化为 最小值
    let ans = - Number.MAX_VALUE
    const n = nums.length
    let curr;
    for (let i = 0; i < n; ++i) {
        // 每次重新开始
        curr = 0
        for (let j = i; j < n; ++j) {
            curr += nums[j]
            ans = Math.max(curr, ans)
        }
    }
    return ans
};
  1. 动态规划. 暴力解法中, 我们是从 0 位置开始, 找出以 0 位置为左边界的所有连续数组, 保存其中的最大值, 然后在从 1 位置开始, 找出以 1 位置为左边界的所有连续数组, 保存其中的最大值... 其实, 对于这种类型的问题, 我们一般都可以往动态规划的方面来想. 我自己的方法是, 倒着思考, 什么意思呢? 对于这个问题, 就是以 i 元素为右边界, 找出以 i 为结尾的连续子数组的最大值, 如何找呢, 首先假设以 i - 1 元素为右边界的连续子数组的最大值为 x, 那么以 i 元素为右边界的连续子数组的最大值为 max(x + nums[i], nums[i]) 这个很好想清楚, 要么是和 i 之前的连续子数组组成更大的子数组, 要么就是自己独立为更大的子数组. 想到这一步, 其实解法就已经很清晰了.

    因为以第 0 位为右边界的子数组的最大值只能为 nums[0], 所以递推下去以第 1 位为右边界的子数组的最大和为 max(nums[0]+nums[1], nums[1]), ... , 这样我们就能得到每个 i 位置上的以它为右边界的最大值, 然后再找出最大的一个即可. 具体见如下代码.

    时间复杂度 O(n), 空间复杂度 O(1)

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    for (let i = 1; i < nums.length; ++i) {
      nums[i] = Math.max(nums[i-1]+nums[i], nums[i])
    }
    let res = Math.max(...nums)
    return res
};