53. 最大子序和

92 阅读1分钟

题目介绍

力扣53题:leetcode-cn.com/problems/ma…

image.png

动态规划

假设num 数组的长度是 n,下标从 0n−1

我们用 f(i) 代表以第 i 个数结尾的「注意这里表示经过num[i]连续子数组的最大和」 ,那么很显然我们要求的答案就是:

image.png

因此我们只需要求出每个位置的 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),其中 nnums 数组的长度。我们只需要遍历一遍数组即可求得答案。
  • 空间复杂度:O(1)。我们只需要常数空间存放若干变量。