题目

https://leetcode.com/problems/maximum-subarray/

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。

自解

暴力解

1
2
3
4
5
6
7
8
9
10
11
def maxSubArray(self, nums: List[int]) -> int:
maxsum=nums[0]
for i in range(len(nums)):
if len(nums)==1:
maxsum=nums[0]
break
sum=nums[i]
for j in range(i+1,len(nums)):
sum=sum+nums[j]
maxsum=max(maxsum,sum)
return maxsum

练了一题后,每道题只能先想到暴力解

[!hint]
假设你在玩一个赚钱游戏,数组里的数字是每一天的盈亏。你的目标是找到一段连续的日子,让总收益最大。

  • 如果之前的总收益是正数,那么加上今天的盈亏,对以后肯定是有好处的。
  • 如果之前的总收益已经变成了负数(欠债了!),那么对于明天来说,带上之前的负债只会让你赚得更少。

在 G 老师的提示下写出下面的解,感觉不是很严谨

1
2
3
4
5
6
7
8
9
10
11
12
13
def maxSubArray(self, nums: List[int]) -> int:
sum=0
maxsum=nums[0]
for i in range(len(nums)):
if len(nums)==1:
sum=nums[0]
break
if sum >=0:
sum=sum+nums[i]
if sum < 0:
sum=0
maxsum=max(sum,maxsum)
return maxsum

题解

前缀和 + 贪心

首先我们需要知道什么是前缀和?前缀和可以简单理解为「一个数组前 𝑛 项的和」。下面是一个例子。

有数组 nums=[1,2,3,4],要想计算子数组 [3,4] 的元素和,可以用前缀和 [1,2,3,4] ,减去另一个前缀和 [1,2] 。

由此,任意子数组的和,都可以表示为两个前缀和的差。我们对数组进行 O(n)O(n) 预处理,能够将单次查询区间和的复杂度降低到 O(1)O(1) 。

求出 nums 的前缀和,就可以用前缀和来表示区间和,问题就变成求最大的区间和,这和买卖股票的最佳时机的思想相似。

1
2
3
4
5
6
7
8
def maxSubArray(self, nums: List[int]) -> int:
presum=presum_min=0
maxsub=-inf
for num in nums:
presum+=num
maxsub=max(maxsub,presum-presum_min)
presum_min=min(presum,presum_min)
return maxsub

写得迷迷糊糊,最后没有对 ans 取最大值。
先计算 maxsub 还是最小前缀和可以用特例来确定。如输入数组为[-1],先更新最小前缀和会导致最后序列和为 0。

参考

https://leetcode.cn/problems/maximum-subarray/solutions/2533977/qian-zhui-he-zuo-fa-ben-zhi-shi-mai-mai-abu71/
https://oi-wiki.org/basic/prefix-sum/


https://yohakuo.github.io/2025/12/28/最大子数组和/
作者
新喀鸦006
发布于
2025年12月28日
许可协议