思路:
这题相对于买卖股票最佳时机2多了一个冷冻期的条件,买卖股票最佳时机2每天只用考虑两个状态,买入股票状态和卖出股票的状态。这题多了一个条件就需要多出一些状态求解,这题就需要总的每天可能分为四个状态:1.持有股票 2.第i天之前不持有股票(前一天是冷冻期,或者前一天超过冷冻期并且不持有股票) 3.第i天卖出股票 4.当天为冷冻期
为什么不把状态二和状态三结合在一起呢?因为状态四是冷冻期,状态四之前的一天一定是状态三,股票卖出的当天。但是如果将状态二和三结合在一起了,那么就无法保证状态四的前一天是刚好卖出股票的那一天,冷冻期的剩余金额一定是卖出股票当天的剩余金额。
动规五部曲:
1.dp[i][j]及其下标的定义:第i天状态j下的最大剩余金额.
2.递推公式:dp[i][0]=max(dp[i-1][0],max(dp[i-1][1],dp[i-1][3])-prices[i])
dp[i][1]=max(dp[i-1][1],dp[i-1][3]);
dp[i][2]=dp[i-1][1]+prices[i]; dp[i-1][3]=dp[i-1][2];
3.初始化:dp[0][0]=-prices[0],其他初始化为0;
4.遍历顺序:从小到大
5.验证dp
class Solution {
public:
int maxProfit(vector& prices) {
int n = prices.size();
if (n == 0) return 0;
vector> dp(n, vector(4, 0));
dp[0][0] -= prices[0]; // 持股票
for (int i = 1; i < n; i++) {
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
dp[i][2] = dp[i - 1][0] + prices[i];
dp[i][3] = dp[i - 1][2];
}
return max(dp[n - 1][3],max(dp[n - 1][1], dp[n - 1][2]));
}
};
思路:
这题相较于买卖股票的最佳时机就主要差别在于递推公式上,当你在第i天持有时没什么差别,要么在前一天就持有了,要么当天买入。但是在卖出的时候就会有所差距,如果是当天卖出,还要减去手续费。dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]-fee);
class Solution {
public:
int maxProfit(vector& prices, int fee) {
int n = prices.size();
vector> dp(n, vector(2, 0));
dp[0][0] -= prices[0]; // 持股票
for (int i = 1; i < n; i++) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i] - fee);
}
return max(dp[n - 1][0], dp[n - 1][1]);
}
};
思路:
最长上升子序列是动规的经典题目,这里dp[i]可以根据dp[j](j
1.dp[i]的定义:
dp[i]表示i之前包括i的以nums[i]结尾最长上升子序列的长度。注意:这个是以nums[i]结尾的最长子序列的长度,而不是遍历到数组i时的最长子序列长度,所以当遍历完nums之后,最长子序列长度不一定是dp[nums.size()-1].可能是前面的元素。
2.状态转移方程。
位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列+1的最大值(前提当然是位置i的值大于j位置的值).所以:if(nums[i]>nums[j]) dp[i]=max(dp[i],dp[j]+1);
3.初始化
每一个i,对应的dp[i]起始大小最少为1.
4.确定遍历顺序:
从前到后遍历
class Solution {
public:
int lengthOfLIS(vector& nums) {
if (nums.size() <= 1) return nums.size();
vector dp(nums.size(), 1);
int result = 0;
for (int i = 1; i < nums.size(); i++) {
for (int j = 0; j < i; j++) {
if (nums[i] > nums[j]) dp[i] = max(dp[i], dp[j] + 1);
}
if (dp[i] > result) result = dp[i]; // 取长的子序列
}
return result;
}
};