给定一个整数数组 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 case:dp[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;
}
};