给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

算法1(动态规划)

时间复杂度:\(O(N)\)
dp数组定义:常规思路下,我们可能会想到用dp[i]代表nums[0...i]最大的子数组和,但是如果这样定义,我们无法通过dp[i]推出dp[i+1],因为拥有最大和的连续子数组不一定和nums[i+1]是连续的。所以为了关联当前的nums[i],我们定义dp[i]代表以nums[i]结尾的连续子数组的最大和。
状态转移:根据dp数组的定义我们可以推出,以nums[i+1]结尾的最大子数组和,要么和以nums[i]结尾的最大和子数组连在一起,要么自己自成一派。所以状态转移方程即为dp[i+1] = max(nums[i], dp[i-1]+nums[i])
base casedp[0]的最大子数组即为nums[0]自己(因为nums[0]之前没有元素了)

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if (nums.size() == 0) return 0;

        vector<int> dp(nums.size());
        dp[0] = nums[0];
        for (int i = 1; i < nums.size(); i ++ ) {
            dp[i] = max(nums[i], dp[i - 1] + nums[i]);
        }

        int res = -1e6;
        for (auto num : dp) {
            res = max(res, num);
        }
        return res;
    }
};

算法2(动态规划优化)

因为dp[i]的值仅与dp[i-1]的值有关,所以我们可以状态压缩进行优化,不需要dp数组存在所有的值,只需要每次更新dp[i-1]dp[i]的值即可。

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if (nums.size() == 0) return 0;

        int dp_0 = nums[0]; //base case
        int dp_1 = 0;
        int res = dp_0; //result
        for (int i = 1; i < nums.size(); i ++ ) {
            dp_1 = max(nums[i], nums[i] + dp_0);
            dp_0 = dp_1;
            res = max(res, dp_0);
        }

        return res;
    }
};