在问 · 算法题解

53. 最大子数组和

中等数组与矩阵动态规划(Kadane)力扣原题 ↗

题目描述

输入整数数组 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

解释:取整个数组,和为 5+4-1+7+8 = 23。

数据范围

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4

进阶:写出 O(n) 解法之后,试着再用分治的思路解一遍。

解题思路:动态规划(Kadane)

以 current 表示必须以当前位置结尾的最大和:若此前和为负就从当前数重新开始,否则接上;同步更新全局 best。

为什么正确

current 是所有以当前下标结尾的非空子数组中的最大和。

复杂度分析

时间 O(n),额外空间 O(n):Python 的 nums[1:] 会创建长度 n-1 的列表切片。

易错点

初始化为 0 会在全负数组时错误返回 0。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def maxSubArray(self, nums):
        current=best=nums[0]
        for x in nums[1:]:
            current=max(x,current+x)
            best=max(best,current)
        return best

载入编辑器,自己跑一遍 →

其他解法

Kadane 与前缀和都是一次遍历、最简洁;分治同样线性,但能扩展成线段树处理区间查询和单点修改。

解法 2:前缀和 + 最小前缀 时间 O(n),空间 O(1)

子数组和等于两个前缀和之差。从左到右累加前缀和 pre,同时记录此前出现过的最小前缀和 min_pre(初始为 0,对应空前缀)。每一步用 pre - min_pre 更新答案,再用 pre 更新 min_pre。

和 Kadane 一样是一次遍历。它把问题转成“买卖股票”式的差值最大化,便于推广到带长度限制等前缀和类问题。

class Solution:
    def maxSubArray(self, nums):
        best = nums[0]
        pre = 0
        min_pre = 0
        for x in nums:
            pre += x
            best = max(best, pre - min_pre)
            min_pre = min(min_pre, pre)
        return best

解法 3:分治 时间 O(n),空间 O(log n)

把区间从中点分成左右两半,分别求出四个量:区间和、最大前缀和、最大后缀和、最大子数组和。合并时,最大前缀和取左前缀与“左区间和 + 右前缀”的较大者,后缀同理。最大子数组和取左答案、右答案、“左后缀 + 右前缀”三者的最大值。

代码更长,递归栈占 O(log n)。它的价值在于合并规则可以直接放进线段树,支持多次查询任意区间的最大子数组和。

class Solution:
    def maxSubArray(self, nums):
        # 返回 (区间和, 最大前缀和, 最大后缀和, 最大子数组和)
        def solve(lo, hi):
            if lo == hi:
                x = nums[lo]
                return x, x, x, x
            mid = (lo + hi) // 2
            ls, lp, lsuf, lbest = solve(lo, mid)
            rs, rp, rsuf, rbest = solve(mid + 1, hi)
            total = ls + rs
            pre = max(lp, ls + rp)
            suf = max(rsuf, rs + lsuf)
            best = max(lbest, rbest, lsuf + rp)
            return total, pre, suf, best

        return solve(0, len(nums) - 1)[3]

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →