题目信息
-
题目:剑指 Offer 42. 连续子数组的最大和
-
时间: 2020-08-30
-
题目链接:Leetcode
-
tag: 动态规划
-
难易程度:简单
-
题目描述:
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
示例:
1 | 输入: nums = [-2,1,-3,4,-1,2,1,-5,4] |
提示
1 | 1. 1 <= arr.length <= 10^5 |
解题思路
本题难点
常见解法 | 时间复杂度 | 空间复杂度 |
---|---|---|
暴力搜索 | O(N^2) | O(1) |
分治思想 | O(NlogN) | O(logN) |
动态规划 | O(N) | O(1) |
具体思路
动态规划
- 状态定义:设动态规划列表 dp ,dp[i]]代表以元素 nums[i] 为结尾的连续子数组最大和。
- 转移方程: 若 dp[i−1]≤0 ,说明 dp[i−1] 对 dp[i] 产生负贡献,即 dp[i−1]+nums[i] 还不如 nums[i] 本身大。
- 当dp[i-1]>0时,执行dp[i]=dp[i-1] + nums[i]
- 当dp[i-1]<0时,执行dp[i]=nums[i]
- **初始状态:**dp[0] = nums[0]
代码
1 | class Solution { |
复杂度分析:
- 时间复杂度 O(N) : 线性遍历数组 nums 即可获得结果,使用 O(N) 时间。
- 空间复杂度 O(1) : 使用常数大小的额外空间。
其他优秀解答
解题思路
分治法,我们把数组nums以中间位置(mid)分为左(left)右(right)两部分. 那么有,
left = nums[0]…nums[m - 1] 和 right = nums[m + 1]…nums[n-1]
最大子序列和的位置有以下三种情况:
- 考虑中间元素
nums[m]
, 跨越左右两部分,这里从中间元素开始,往左求出后缀最大,往右求出前缀最大, 保持连续性。 - 不考虑中间元素,最大子序列和出现在左半部分,递归求解左边部分最大子序列和
- 不考虑中间元素,最大子序列和出现在右半部分,递归求解右边部分最大子序列和
代码
1 | class MaximumSubarrayDivideConquer { |