309.最佳买卖股票时机含冷冻期
思路:
这题相对于买卖股票最佳时机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<int>& prices) { int n = prices.size(); if (n == 0) return 0; vector<vector<int>> dp(n, vector<int>(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])); }};
714.买卖股票的最佳时机含手续费
思路:
这题相较于买卖股票的最佳时机就主要差别在于递推公式上,当你在第i天持有时没什么差别,要么在前一天就持有了,要么当天买入。但是在卖出的时候就会有所差距,如果是当天卖出,还要减去手续费。dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i]-fee);
class Solution {public: int maxProfit(vector<int>& prices, int fee) { int n = prices.size(); vector<vector<int>> dp(n, vector<int>(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]); }};
300.最长递增子序列
思路:
最长上升子序列是动规的经典题目,这里dp[i]可以根据dp[j](j<i)推导出来,动规五部曲分析一波:
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<int>& nums) { if (nums.size() <= 1) return nums.size(); vector<int> 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; }};