题目链接
https://leetcode-cn.com/problems/lian-xu-zi-shu-zu-de-zui-da-he-lcof/
题目介绍
剑指 Offer 42. 连续子数组的最大和
输入一个整型数组,数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例1:
输入: nums = [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
for i in range(1, n):
nums[i] += max(nums[i - 1], 0)
return max(nums)
思路
首先,拿到本题,大家应该很容易联想到高中时做过的数列题吧?曾经有一类题,专门让你求Sn最大,它的思路是什么呢?
1. 全部递增,基本不会考
2. 先增后减,是不是只要找到an < 0的那个就行了,因为什么呢?第n项你加上一个负数,我反而还变小了,不是吃饱了撑的
3. 先减后增,有本题无关,跳过
那么,回到这道题,要求连续的子数组和最大,是不是保证一直加正数就行了,那么他的状态转移方程怎么写?
我们上次说过了,要什么就设什么,就设dp[i] 为截止到 nums[i] 的最大和
,那么状态转移方程如何写出呢?
dp[i] = max(dp[i-1] + nums[i],nums[i])
当然本题如果初始化,dp[0] = nums[0] ,其他的显得没有必要。那么,本题就可以不必按照严格的框架写
我们这里将nums[0] 保持不变,从nums[1] 开始,如果发现它的前一项是负的,那么就保持不变,如果是正的,就上去,最后是不是只要返回max(nums)
需要注意的是,一般不要动原数组,会出现索引问题,因为本题无论如何,不会出现数组元素的增减,可以这样用
举个例子,我想把这个数组的负数全部移除
nums = [-1,-2,-3,1,2,3]
for i in nums:
if i < 0:
nums.remove(i)
print(nums)
#[-2,1,2,3]
为什么不行呢?
因为一开始的for语句的逻辑与执行一次remove操作的for语句逻辑变了
当移除-1之后,nums = [-2,-3,1,2,3],这个时候再回到for循环,你会发现,i的逻辑应该是第二个数,那么此时的第二个数是-3,-2就这么理所应当地被错过了
拓展
做了几道DP题,心中应该有数了,凡是需要用DP解决的,都会涉及到用前一项去转移,那么解决核心就是找出状态转移方程以及基例
大家觉得写的好的欢迎去github给我点小星星,让更多人看到
https://github.com/sherlcok314159/leetcode-python-3/blob/main/md/son_array.md