代码随想录算法训练营第36天|188.买卖股票的最佳时机IV、309.最佳买卖股票时机含冷冻期、714.买卖股票的最佳时机含手续费
LeetCode188
2025-03-09 17:36:31 星期日
题目描述:力扣188
文档讲解:代码随想录(programmercarl)188.买卖股票的最佳时机IV
视频讲解:《代码随想录》算法视频公开课:动态规划来决定最佳时机,至多可以买卖K次!| LeetCode:188.买卖股票最佳时机4
代码随想录视频内容简记
本题和上一题的主要区别就是最多可以买卖k次,不是两次了。其实一看到这里我想到了递归,但是其实也不用,直接新建2k个状态的数组就可以,然后用for循环进行初始化和递推即可
梳理
-
确定dp[i][j]数组的含义,表示第i天持有或者不持有所能得到的最大利润是dp[i][j]
-
确定递推公式,首先明确的,奇数表示持有,偶数表示不持有
for (int j = 0; j < 2 * k; j+=2) {
dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]);
dp[i][j + 2] = max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]);
}
- 初始化dp数组,这个也用for循环,在奇数持有的情况下,都初始化为-prices[i],在偶数不持有的情况下,都是0就不用再单独初始化
for (int j = 1; j < 2 * k; j+=2) {
dp[i][j] = -prices[0];
}
-
确定遍历顺序,遍历仍然是从前向后即可
-
打印dp数组
LeetCode测试
这是第四道困难的题,写的时候注意小细节,一开始又j++去了,说找不到哪里的问题
点击查看代码
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(2 * k + 1, 0));
for (int j = 1; j < 2 * k; j+=2) {
dp[0][j] = -prices[0];
}
for (int i = 1; i < prices.size(); i++) {
// 递推
for (int j = 0; j < 2 * k; j+=2) {
dp[i][j + 1] = max(dp[i - 1][j + 1], dp[i - 1][j] - prices[i]);
dp[i][j + 2] = max(dp[i - 1][j + 2], dp[i - 1][j + 1] + prices[i]);
}
}
return dp[prices.size() - 1][2 * k];
}
};
LeetCode309
题目描述:力扣309
文档讲解:代码随想录(programmercarl)309.最佳买卖股票时机含冷冻期
视频讲解:《代码随想录》算法视频公开课:动态规划来决定最佳时机,这次有冷冻期!| LeetCode:309.买卖股票的最佳时机含冷冻期
代码随想录视频内容简记
冷冻期:卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
这个题最特殊的地方就是加上了冷冻期,这个冷冻期主要是限制了不能在卖出的第二天就买入。在冷冻期之后可能会有一个很长的保持卖出股票的状态,也可能在冷冻期之后第二天就买入,这两种都是可以的
所以,主要分为四个状态
-
保持股票
-
保持股票卖出
-
卖出股票
-
冷冻期
为什么把之前的不保持股票拆分开来时保持股票卖出和卖出股票?就是因为如果有冷冻期的前一个状态一定是卖出股票,不是保持股票卖出的状态,另外冷冻期之后会有一个“空窗期”,这个状态不能操作股票,所以只能是保持股票卖出
梳理
-
确定dp[i][j]数组的定义,表示第i天状态j所能获得的最大利润
-
确定递推公式,
保持股票___卖出股票___冷冻期___|保持股票卖出___|___|___|__|__保持股票
-
保持股票,其前一个状态可以还是保持股票,也可以是保持股票卖出,也可以是冷冻期,共有三种
-
保持股票卖出,其前一个状态可以还是保持股票卖出,就是延续,也可以是冷冻期,
-
卖出股票的前一个状态一定是保持股票
-
冷冻期的前一个状态一定是卖出股票
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i], dp[i - 1][3] - 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]
- 初始化dp数组,也就是初始化第0天的。这里要注意的是,因为第0天的保持股票卖出,卖出股票和冷冻期都是非法的,所以不能从定义上考虑,直接从递推公式推导的角度进行初始化即可
dp[0][0] = -prices[0];
dp[0][1] = 0;
dp[0][2] = 0;
dp[0][3] = 0;
-
确定遍历顺序,从前向后即可。
-
打印dp数组
LeetCode测试
这里需要注意的是,最后的四个状态中有三个都是未持有股票的状态,所以需要返回的是他们三个的最大值
点击查看代码
class Solution {
public:
int maxProfit(vector<int>& prices) {
vector<vector<int>> dp(prices.size(), vector<int>(5, 0));
dp[0][0] = -prices[0];
dp[0][1] = 0;
dp[0][2] = 0;
dp[0][3] = 0;
for (int i = 1; i < prices.size(); i++) {
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][1] - prices[i], dp[i - 1][3] - 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];
// cout << dp[i][j] << ' ';
}
return max(max(dp[prices.size() - 1][1], dp[prices.size() - 1][2]), dp[prices.size() - 1][3]);
}
};
LeetCode714
题目描述:力扣714
文档讲解:代码随想录(programmercarl)714.买卖股票的最佳时机含手续费
视频讲解:《代码随想录》算法视频公开课:动态规划来决定最佳时机,这次含手续费!| LeetCode:714.买卖股票的最佳时机含手续费
代码随想录视频内容简记
本题和买卖股票Ⅱ的差别就在于一个手续费,所以只需要修改核心的部分就是不持有股票的状态
买卖股票系列完结
LeetCode测试
点击查看代码
class Solution {
public:
int maxProfit(vector<int>& prices, int fee) {
vector<vector<int>> dp(prices.size(), vector(2, 0));
dp[0][0] = -prices[0];
dp[0][1] = 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] - fee);
}
return dp[prices.size() - 1][1];
}
};
浙公网安备 33010602011771号