题目介绍
力扣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)。我们只需要常数空间存放若干变量。