--------------------------------二刷2021/1/25--------------------------
要注意dp观察的是前一个dp[i -1]有没有必要加上自己,而不是自己是不是大于0
----------------------------------一刷--------------------------------------
也就是最大子序列和问题,原来在LeetCode才算中等题
题目描述
解法 贪心算法
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int len = nums.size() - 1;
int flag = 0;
int max = -1000000;
int count = 0;
int index = 0;
for(int i = 0; i <= len; i ++) {
if(nums[i] > 0) {
flag = 1;
index = i;
break;
}
}
//如果都是负数直接取负数里面的最大值。
if(flag == 0) {
for(int num : nums)
if(num > max) max = num;
return max;
}
for(int i = index ; i <= len ; i ++) {
//遇到一个数字小于0,就保存一个记录,判断一下当前count会不会大于之前保存的count
if(nums[i] < 0) {
if(count > max) max = count;
count += nums[i];
//当count<0时说明这段子序列肯定不在最大子序列之中,将count设为0重新开始。
if(count < 0)
count = 0;
continue;
}
//遇到一个数字大于0直接增加count
count += nums[i];
}
//如果在统计结束的时候没有遇到负数,max不会更新,所以结束之前增加一段判断。
if(count > max) max = count;
return max;
}
};
时间复杂度O(n),空间复杂度O(1),复杂度是没什么问题,但是代码写得稀烂
主要来说有两个可以优化的点
1.全负数情况
2.最后一次的判断
想了许久还是没有找到突破口,只能另寻其路
动态规划
显然这个题目很适合动态规划
- dp数组含义
dp[i],以nums[i]为结尾的子序列的连续子数组最大和 - dp方程
根据dp[i-1]来判断
如果dp[i-1]<=0 dp[i]=nums[i]
如果dp[i-1]>0 dp[i]=nums[i]+dp[i-1] - 初始状态
dp[0]= nums[0]
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int len = nums.size();
vector<int> dp (len, 0);
dp[0] = nums[0];
int m = nums[0],ans = nums[0];
for(int i = 1; i < len; i ++) {
if(dp[i - 1] <= 0) dp[i] = nums[i];
else dp[i] = dp[i - 1] + nums[i];
ans = max(ans,dp[i]);
}
return ans;
}
};
这样需要O(N)的空间复杂度
看到大佬的题解说,由于dp[i]只用到了nums[i],所以可以将原数组作为dp数组,这样空间复杂度就可以降为O(1)
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int len = nums.size();
int ans = nums[0];
for(int i = 1; i < len; i ++) {
if(nums[i - 1] > 0) nums[i] = nums[i - 1] + nums[i];
ans = max(ans,nums[i]);
}
return ans;
}
};