题目介绍


剑指 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解决的,都会涉及到用前一项去转移,那么解决核心就是找出状态转移方程以及基例