【题目要求】
给你一个整数数组 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
【解题思路】
核心观念:编程实际上是用计算机实现人工能干的事情。
因此解题可以遵循“人工推导——从个体到群体——从特殊到普遍”的思路,即从个例推出通解。
这道题的处理需要稍微灵活点,拿[-2, 1, -3, 4, -1, 2, 1, -5, 4]为例,如果我们人工来做,似乎一时间也没啥头绪。。但是凭借经验,至少我们可以知道,如果一个数组中的元素都是正数,显然最大和连续子数组就是它本身,也就是说我们要尽可能多地把正数放到最后要求的子数组中。那么我们常规遍历一遍数组:
R1:首先拿出-2,由于这是第一个数字,手头上拿出来的没有其他数字了,所以目前最大是-2
R2:接着拿出1,可以发现,[-2, 1]这个子数组的和是-1,比R1的最大结果要大,但是,如果我们只拿1,
把前面的-2丢掉,是不是更大了,-2<(-2+1)<1,那此时最大和子数组应该是[1]
R3:拿出-3,如果放到前面的最大和子数组中变成[1, -3]显然结果更小了,所以最大子数组还是[1]
R4:继续拿出4,显然单是一个4就比前面的最大和子数组[1]要大了,这时候得想想,能不能让1和4加到一起
呢,毕竟1+4=5,只要两者中间的元素不捣乱,那最大值就又能变大了,那我们再考虑把之前丢掉的-3拿
回来,组成[1, -3, 4],和为2,显然现在max更新成[4],4前面的元素都得丢掉,毕竟加上了结果反而
更小
R5:接下来拿出-1,显然-1<4,最大和子数组为[4],继续遍历
R6:拿出2,2<4,最大和子数组是[4],但是这时候还是得想想,能不能让4和2加到一起呢,如果二者中间的
元素识相,那最大值就又变大了,那我们再考虑把之前丢掉的-1拿回来组成[4, -1, 2],和为5,显然现
在max更新成[4, -1, 2],虽然二者中间的不是正数,但是组合起来的子数组和还是变大了一丢丢的
R7:当前拿出来的是1,是个正数,显然加上去max可以更新为[4, -1, 2, 1]
R8:接下来拿出-5,前面的值加上-5就变小了,所以最大和子数组不变
R9:最后一个是4,考虑一下能不能让4也加进去呢,但因为是连续子数组,所以还得把前面的-5也加上,子数组变成[4, -1, 2, 1, -5, 4],比原先的最大和子数组要小,那么到这里,遍历完数组之后,结果就是[4, -1, 2, 1],值为6。有没有发现,上述的过程中我们一直在考虑当前遍历到一个元素时,到底需不需要把该元素之前的最大值加进去,但是由于是连续子数组,还需考虑当前值和当前值之前最大值二者之间的元素,比如遍历到4的时候,考虑要不要加上前面的最大值1,但是连续子数组就变成了[1, -3, 4],更小了,所以不需要加上之前的值,那么转换成代码可以写成:
【运行代码】
class Solution(object):
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
# 定义prev用于存储当前元素之前的最大值
prev = 0
# 初始化结果变量
res = -int(1e9)
# 遍历数组
for li in nums:
# 每次更新当前元素及其之前的最大值,这里可以拿实例手动推导一下,会发现跟前面的推导
# 流程是一样的,这里的max(prev+li, li)就是实现了每次考虑是否加上前面的最大值,但是
# 同时还需要加上二者之间的元素,比如遍历到4,前面最大的元素是1, 由于上一步遍历到-3
# 时,最大值是1-3=-2,所以此时的prev是-2,那显然max(-2+4, 4)结果为4
prev = max(prev+li, li)
# 更新最大结果
res = max(res, prev)
return res
【运行结果】