之前一篇动态规划–股票系列(一):买卖股票的最佳时机讲解了股票系列中买卖多次且k值确定下所得的最大利润。现在来分析一下,力扣上其他题目。
可解决力扣题目:122、309、714
122. 买卖股票的最佳时机 II
解法1:贪心
假如第0天买入,第3天卖出,那么获得的利润为prices[3]-prices[0]
可以分解为:(prices[3]-prices[2])+(prices[2]-prices[1])+(prices[1]-prices[0])
,那么问题转化为,每天利润,收集正利润就可以。
整体代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int res = 0;
for(int i = 1; i < prices.size(); i++){
// 只收集每天的正利润,从第二天开始产生利润
if(prices[i] - prices[i - 1] > 0){
res += prices[i] - prices[i - 1];
}
}
return res;
}
};
解法2:动态规划
跟121. 买卖股票的最佳时机唯一不同的地方,在于本题可以买卖多次,体现在代码中也就是当你买入(持有)的时候,需要考虑上次卖出后(不持有)对本次买入的影响!
整体代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
// 动态规划
// dp[i][0]--第 i 天持有股票所得最大现金
// dp[i][1]--第 i 天不持有股票所得最大现金
vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
dp[0][0] = -prices[0];
for(int i = 1; i < prices.size(); 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]);
}
return dp[prices.size() - 1][1];
}
};
309. 最佳买卖股票时机含冷冻期
思路:4个状态
当天状态如下:
- 0–买入
- 1–两天前卖出并且度过冷冻期,现在保持状态(还未进行下一次买入)
- 2–卖出
- 3–处于冷冻期,仅保持一天,也就是前一天是卖出状态
状态定义:dp[i][j]
中,i
表示第i
天,j∈[0,3]
,表示一天中的4个状态
递推方程:
-
对于
dp[i][0]
,也就是买入状态,有3
种情况:-
前一天就买入,但是一直保持这种状态不操作,即
dp[i][0]=dp[i - 1][0]
-
今天买入,那么前一天有两种情况
-
前一天是冷冻期,那么
dp[i][0]=dp[i - 1][3]-prices[i]
-
两天前卖出并且度过冷冻期后,没有操作(至少一天),即
dp[i][0]=dp[i - 1][1]-prices[i]
-
取三者最大值。
-
-
对于
dp[i][1]
,有2
种情况:-
前一天是冷冻期,
dp[i][1]=dp[i-1][3]
-
两天前是冷冻期,但是还没买入,保持
dp[i][1]=dp[i-1][1]
-
-
对于
dp[i][2]
,
今天卖出,即dp[i][2]=dp[i-1][0]+prices[i]
*** -
对于
dp[i][3]
,
即今天冷冻期,那么就是前一天当天一定是卖出,即dp[i][3]=dp[i - 1][2]
要时刻理解,各个状态下的含义,才不会晕头转向。整体代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
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]; // 冷冻期,只保持 1 天
}
return max({dp[n - 1][1], dp[n - 1][2], dp[n - 1][3]});
}
};
714. 买卖股票的最佳时机含手续费
思路:
相比于122. 买卖股票的最佳时机 II,本题多了一个手续费,那么只需要在卖出的时候支付手续费,就可以。另一个不同之处在于,本题多了手续费,也就是说有可能买入状态也可能是最大利润(当手续费高于所得时),所以返回值需要返回买入卖出两者的最大值。
122题代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices) {
// dp[i][0] -- 第i天 持有 股票所得现金
// dp[i][1] -- 第i天 不持有 股票所得现金
vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
dp[0][0] = -prices[0];
for(int i = 1; i < prices.size(); 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]);
}
return dp[prices.size() - 1][1];
}
};
本题整体代码如下:
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
int n = prices.size();
// dp[i][0] -- 第i天 持有 股票所得现金
// dp[i][1] -- 第i天 不持有 股票所得现金
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]);
}
};
参考资料:公众号代码随想录