版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/dpengwang/article/details/86656101
方法1:直觉法
求连续子数组的最大和,就是相当于用一个框框起数组中的若干个数,使其和最大,这个框该怎么选?
我们用curr_sum表示当前框里框住的元素和。
首先固定框的左边,移动框的右边,如果curr_sum大于0,我们就右移右边界并求和,记录当前的最大值。如果curr_sum小于0,我们就将框的左边移动到当前位置(代码中的表现就是让curr_sum归零),然后再右移右边界并求curr_sum,记录当前的最大值
为什么要在curr_sum小于等于0的时候将框的左边界移动到当前位置?
因被框住的部分和小于等于0,他们对后面产生的和只会有减少左右不会有增加作用,所以要舍弃掉,当前的元素是一个leader,之前被框住的一坨是一个小团队A(假设不用按人头发工资),现在leader和A要组成更强的团队,如果整个A对外的输出都不是正的,那为啥还要跟你组队呢。只要A的输出为正的,那就留着。
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
curr_sum = -float("inf")
res = curr_sum
for i in nums:
if curr_sum < 0:
curr_sum = i
else:
curr_sum += i
res = max(res, curr_sum)
return res
方法2:dp法
其实就是直觉法更形式化的方法,我们用dp[i]表示包含第index=i元素的最大连续子数组和,那么很容易写出递推方程
dp[i] = a[i] if dp[i-1] <=0 else dp[i-1] + a[i]
即
dp[i] = max(a[i] + dp[i-1], a[i])
现实中的解释就是,如果dp[i-1]小于等于0,那你对我的增加一点用处都没有,那么就舍弃掉你。
class Solution:
def maxSubArray(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
res =nums[0]
dp = [nums[0]]*len(nums)
for i in range(1,len(nums)):
dp[i] = max(dp[i-1]+nums[i], nums[i])
res = max(res, dp[i])
return res
方法3: 递增栈法
我们要找最大和子数组,也就是最大的
(i<j),其中
表示array[0:i]的和,不考虑时间复杂度的话,两个for循环即可解决问题。我们通过维护一个递增栈,就能用O(n)的时间复杂度来求得最大差。
我们先求
nums = [-2, 1, -3 ,4, -1, 2, 1, -5, 4]
sum = [-2, -1, -4, 0, -1, 1, 2, -3, 1]
我们维护一个递增栈,创建一个stack,遍历sum中的元素并按照如下方法入栈
- 如果栈为空,将当前元素入栈
- 如果栈顶元素小于当前元素,将当前元素入栈
- 如果栈顶元素大于当前元素,popstack,直到栈顶元素小于当前元素
- 每次操作完毕后求栈顶减去栈底元素来更新res
因为是顺序入栈的,所以我们可以保证栈底元素的index总是小于栈顶元素的index,因为栈是递减的,所以在index=i的时候,栈底存储的一定是sum[0:i]中最小的元素,栈顶一定是sum[0:i]中最大的元素。
这里有个小trick,我们把res的初始值设为nums中的最大值,这样可以避免nums全为负导致的异常情况,把stack初始值设为0可以避免num全为正导致的异常情况。
stack的出栈入栈情况如下:
i | sum[i] | stack | res |
---|---|---|---|
-1 | [0] | 4 | |
0 | -2 | [-2] | 4 |
1 | -1 | [-2,-1] | 4 |
3 | -4 | [-4] | 4 |
4 | 0 | [-4,0] | 4 |
5 | -1 | [-4,-1] | 4 |
6 | 1 | [-4,-1,1] | 5 |
7 | 2 | [-4,-1,2] | 6 |
8 | -3 | [-4,-3] | 6 |
9 | 1 | [-4,-3,1] | 6 |
AC代码
class Solution:
def maxSubArray(self,nums):
"""
:type nums: List[int]
:rtype: int
"""
res = nums[0]
for i in range(len(nums)):
res = max(res, nums[i])
if i == 0:
continue
else:
nums[i] += nums[i-1]
stack = [0]
for number in nums:
if len(stack) == 0 or (len(stack)!=0 and stack[-1] < number):
stack.append(number)
res = max(res, stack[-1] - stack[0])
else:
while(len(stack) and stack[-1] >= number):
stack.pop()
stack.append(number)
return res