动态规划的问题都是牺牲空间换取时间,用内存存储子问题的计算结果,使得之后用到信息时不再重复计算,直接获取计算过的结果即可。动态规划的问题真不好想,除非递推公式比较明显。
1. Maximum Subarray
介绍:
Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [-2,1,-3,4,-1,2,1,-5,4], the contiguous subarray [4,-1,2,1] has the largest sum = 6.
题意:
找到最大连续子串和。
思路:
这道题可以有几种思路,但是具体的想法都差不太多。
无论是哪种动态规划的思路,最重要的共同点都是定义子问题,这里定义a[i]为以下标i结尾的最大连续子串和(实际上做多了你会发现这样定义子问题是动态规划的一种很常见的想法)
那么很容易得到推导公式:
a[i]=max(nums[i],a[i-1]+nums[i])
以下标i结尾的a[i]肯定要有nums[i],所以就是比较i前面的那段子串需不需要的区别而已,如果a[i-1]大于0,那么需要,否则不需要。然后每次更新保留a[i]的最大值即可,从这个思路出发就能得到V1版本的代码了。
实际上大可不需要使用数组,因为在每次循环比较之后,数组保存的值就失去价值了,因而我们可以改进为当个变量,这就是V2版本的代码了,在这种时候就不用对n为1的情况单独讨论了。
还有一种思路是如果a>=0,则a+=nums[i],否则a=nums[i],其实这种思路不就是把a=max(a+nums[i], nums[i]);拆开来了嘛!万变不离其宗。
2. 代码
V1
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int a[n] = {INT_MIN};
//设置当n为1的情况
a[0] = nums[0];
int res = nums[0];
for (int i = 1; i <= n-1; ++i) {
a[i] = max(nums[i], a[i-1]+nums[i]);
res = max(a[i], res);
}
return res;
}
};
V2
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
int res = INT_MIN, a = 0;
for(int i=0; i < n; ++i)
{
a = max(a+nums[i], nums[i]);
res = max(res, a);
}
return res;
}
};