题目介绍
力扣53题:leetcode-cn.com/problems/ma…
动态规划
假设num
数组的长度是 n
,下标从 0
到 n−1
。
我们用 f(i)
代表以第 i
个数结尾的「注意这里表示经过num[i]连续子数组的最大和」 ,那么很显然我们要求的答案就是:
因此我们只需要求出每个位置的 f(i)
,然后返回 f
数组中的最大值即可。那么我们如何求 f(i)
呢?我们可以考虑 nums[i]
单独成为一段还是加入 f(i−1)
对应的那一段,这取决于 nums[i]
和 f(i−1) + nums[i]
的大小,我们希望获得一个比较大的,于是可以写出这样的动态规划转移方程:
f(i) = max{f(i−1) + nums[i], nums[i])
代码如下:
class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = nums[0];
int maxAns = dp[0];
for(int i = 1; i < nums.length; i++) {
dp[i] = Math.max((dp[i-1] + nums[i]), nums[i]);
maxAns = Math.max(maxAns, dp[i]);
}
return maxAns;
}
}
不难给出一个时间复杂度 O(n)
、空间复杂度 O(n)
的实现,即用一个 f
数组来保存 f(i)
的值,用一个循环求出所有 f(i)
。考虑到 f(i)
只和f(i−1)
相关,于是我们可以只用一个变量 pre
来维护对于当前f(i)
的f(i−1)
的值是多少,从而让空间复杂度降低到O(1)
。
class Solution {
public int maxSubArray(int[] nums) {
int pre = 0, maxAns = nums[0];
for (int x : nums) {
pre = Math.max(pre + x, x);
maxAns = Math.max(maxAns, pre);
}
return maxAns;
}
}
复杂度
- 时间复杂度:
O(n)
,其中n
为nums
数组的长度。我们只需要遍历一遍数组即可求得答案。 - 空间复杂度:
O(1)
。我们只需要常数空间存放若干变量。