Problem_link: 53. 最大子数组和
方法一 O(N) C(N)
思路
题目要求找出前n个元素连续和最大的子序列,遇到这种有子问题求最值的题目都可以使用动态规划解决。
解题方法
定义 d p [ i ] dp[i] dp[i]表示前 i + 1 i+1 i+1个元素连续和的最大值。
对任意nums[i]都可以作为前i个元素累加的结尾或是下一个子序的开头。
比如nums = [-2,1]
,前1个元素时必须选:
- 所以此时的最大值(
m
a
x
max
max)是
-2
; - dp[0]也是
-2
。
前2个元素的时:
- 可以选择累加( d p [ i − 1 ] + n u m s [ i ] dp[i-1]+nums[i] dp[i−1]+nums[i]),即作为前i+1个元素累加的结尾;
- 不累加,就是 d p [ i ] = n u m s [ i ] dp[i] = nums[i] dp[i]=nums[i],即作为下一个子序的开头。
- 取两种选择中的较大值,一个很简单的逻辑,如果前i+1个元素的合还没有nums[i]一个元素值大,那么选nums[i]就行了。
返回 d p dp dp数组中的最大值即可。
复杂度
-
时间复杂度:
O ( n ) O(n) O(n) -
空间复杂度:
O ( n ) O(n) O(n)
Code
class Solution {
public:
int max(int a,int b){
return a>b?a:b;
}
int maxSubArray(vector<int>& nums) {
vector<int> dp(nums.size(),0); // 长度和nums一直,元素初始化为0
dp[0] = nums[0]; // 初始化
int res = dp[0];
for(int i=1;i<nums.size();i++){ // 遍历所有
dp[i] = max(dp[i-1]+nums[i],nums[i]);
res = max(dp[i],res); // 更新最大值
}
return res;
}
};
可以发现每次递推只用了 d p [ i − 1 ] 和 d p [ i ] dp[i-1]和dp[i] dp[i−1]和dp[i]两个,所以只需要用变量保存,就可以优化到常量空间。
方法一空间优化 C(1)
class Solution {
public:
int max(int a,int b){
return a>b?a:b;
}
int maxSubArray(vector<int>& nums) {
int res = -100000; // 初始化最大值
int ans = 0; // 表示前i+1个元素的合,没有元素则为0
for(auto x:nums){
ans += x;
res = max(ans,res); // dp[i] = max(dp[i-1]+nums[i],res)
// 如果ans已经是负数了,它就无法为后面的元素提供增量
// 所以就把开头移到新的位置就行了
if(ans<0) ans = 0;
}
return res;
}
};
总结
这道题就好比:过去如果不能是你未来的阶梯,那就抛弃它,从当下开始。现实总是更复杂,不能一句概括