一、买卖股票的最佳时机含冷冻期
题目解析

给定一个整数数组 prices,其中prices[i]表示第 i 天的股票价格;计算 最大收益
约束条件:
- 不能同时参与多笔交易(已有股票就不能再买入了)
- 卖出股票后,有一天的冷静期
算法思路
状态表示:
对于这道题,第 i 天结束 存在三种状态:持有股票(买入) 、不持有股票,处于冷冻期(冷冻) 、不持有股票,不处于冷冻期(可交易)
所以,这里就需要表示三种状态下的最大收益:
dp[i][0]: 第 i 天结束处于 买入 状态,此时的最大收益dp[i][1]: 第 i 天结束处于 冷冻 状态,此时的最大收益dp[i][2]: 第 i 天结束处于 可交易 状态,此时的最大收益
状态转移方程:
这里只靠想象,去找这个状态转移还是比较费劲的,可以自己画一个图,思考状态之间是如何转化的:

如上图,状态转移清晰可见,状态转移方程:
dp[i][0] = max(dp[i-1][0],dp[i-1][2] - prices[i])dp[i][1] = dp[i-1][0] + prices[i]dp[i][2] = max(dp[i-1][2],dp[i-1][1])
初始化
这里初始化dp[0][0]、dp[0][1]、dp[0][2],第一结束处于买入、冷冻、可交易状态的最大收益即可。
返回值
题目要求的是:最大利润,最后一天(n-1)再持有股票(买入状态)没有意义;所以,最终结果应该是 dp[n-1][1]、dp[n-1][2]中的最大值。
代码实现
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<vector<int>> dp(n, vector<int>(3, 0));
dp[0][0] = -prices[0];
for (int i = 1; i < n; i++) {
dp[i][0] = max(dp[i - 1][0], dp[i - 1][2] - prices[i]);
dp[i][1] = dp[i - 1][0] + prices[i];
dp[i][2] = max(dp[i - 1][2], dp[i - 1][1]);
}
return max(dp[n - 1][1], dp[n - 1][2]);
}
};
二、买卖股票的最佳时机含手续费
题目解析

给定一个数组 proces和一个整数fee,proces[i]表示第 i 天的股票价格;fee表示交易股票的手续费用(每笔交易只需支付一次)
约束条件
- 不能同时参与多笔交易(已有股票就不能再买入了)
- 每笔交易需要支付手续费用
算法思路
状态表示
这道题目,第 i 天结束,只有两种状态:持有股票、不持有股票
dp[i][0]: 表示第 i 天结束,持有股票时的最大收益dp[i][1]: 表示第 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)
初始化
这里只需初始化第 1 天结束,持有股票和不持有股票时的最大收益即可。(dp[0][0] 和 dp[0][1])
返回值
题目要求的是最大收益,最终结果存储在 dp[n-1][1]中(最后一天结束,持有股票状态无意义)
代码实现
cpp
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 dp[n - 1][1];
}
};
三、买卖股票的最佳时机 III
题目解析

给定一个数组 proces,proces[i]表示第 i 天的股票价格;
约束条件
- 不能同时参与多笔交易(已有股票就不能再买入了)
- 最多只能进行 2 笔交易
算法思路
这道题没有交易冷冻期,交易手续费之类的;要求只能进行 2 笔交易
对于第 i 天结束,这个状态就有 6种:
进行了 0 次交易:持有股票(买入状态) 、不持有股票(卖出状态)
进行了 1 次交易:持有股票(买入状态) 、不持有股票(卖出状态)
进行了 2 次交易:持有股票(买入状态) 、不持有股票(卖出状态)
一次交易:股票买入 - 股票卖出
这里当股票卖出之后,认为此次交易才算完成
状态表示:
f[i][0]:第 i 天结束,进行了 0 次交易,处于 买入 状态的最大利润f[i][1]:第 i 天结束,进行了 1 次交易,处于 买入 状态的最大利润f[i][2]:第 i 天结束,进行了 2 次交易,处于 买入 状态的最大利润g[i][0]:第 i 天结束,进行了 0 次交易,处于 卖出 状态的最大利润g[i][1]:第 i 天结束,进行了 1 次交易,处于 卖出 状态的最大利润g[i][2]:第 i 天结束,进行了 2 次交易,处于 卖出 状态的最大利润
状态转移方程:
f[i][0] = max(f[i-1][0], g[i-1][0] - prices[i])f[i][1] = max(f[i-1][1], g[i-1][1] - prices[i])f[i][2] = max(f[i-1][2], g[i-1][2] - prices[i])g[i][0] = g[i-1][0]g[i][1] = max(g[i-1][1], f[i-1][0] + prices[i])g[i][2] = max(g[i-1][2], f[i-1][1] + prices[i])
初始化
这里初始化 第 1 天结束时,0 次交易,处于 买入 状态的最大收益即可(第一天结束,进行 0 笔交易,处于卖出状态)
为了不影响最终结果,第 1 天结束,进行 1、2 笔交易最大收益 都设置成 -0x3f3f3f
返回值
要求最大收益,最终结果(第 n 天结束,进行了 0、1、2次交易,处于 卖出(不持有股票)的最大收益)
即 max(g[n-1][0], g[n-1][1], g[n-1][2])
代码实现
cpp
class Solution {
public:
int maxProfit(vector<int>& prices) {
int n = prices.size();
vector<vector<int>> f(n, vector<int>(3, 0));
vector<vector<int>> g(n, vector<int>(3, 0));
f[0][0] = -prices[0];
f[0][1] = f[0][2] = g[0][1] = g[0][2] = -0x3f3f3f;
for (int i = 1; i < n; i++) {
f[i][0] = max(f[i - 1][0], g[i - 1][0] - prices[i]);
f[i][1] = max(f[i - 1][1], g[i - 1][1] - prices[i]);
f[i][2] = max(f[i - 1][2], g[i - 1][2] - prices[i]);
g[i][0] = g[i - 1][0];
g[i][1] = max(g[i - 1][1], f[i - 1][0] + prices[i]);
g[i][2] = max(g[i - 1][2], f[i - 1][1] + prices[i]);
}
return max(max(g[n - 1][0], g[n - 1][1]), g[n - 1][2]);
}
};
四、买卖股票的最佳时机 IV
题目解析

给定一个数组 proces和一个整数 k;proces[i]表示第 i 天的股票价格,k 表示最多的交易次数
约束条件
- 不能同时参与多笔交易(已有股票就不能再买入了)
- 最多只能进行 k 笔交易
算法思路
对于第 i 天结束,这个状态有 2*k 种,很显然使用有限的状态是表示不过来了;
这里就可以使用二维数组(甚至三维)来表示:
状态表示
f[i][j]:第 i 天结束,进行了 j 次交易,处于 买入 状态的最大利润g[i][j]:第 i 天结束,进行了 j 次交易,处于 卖出 状态的最大利润
状态转移方程
f[i][j] = max(f[i-1][j], g[i-1][j] - prices[i])g[i][j] = max(g[i-1][j], f[i-1][j-1] + prices[i])
注意 : 在填 g[i][0]时,会用到 f[i-1][-1](越界);这里需要进行特殊判断
初始化
这里初始化 第 1 天结束时,0 次交易,处于 买入 状态的最大收益(-prices[i])、第一天结束,进行 0 笔交易,处于卖出状态,最大收益为 0
为了不影响最终结果,第 i(i > 0) 天结束,进行 0~k 笔交易最大收益 都设置成 -0x3f3f3f
最终结果
求最大利润,最终结果就应该是 第 n-1 天结束,进行 0~k 笔交易,处于卖出状态的最大利润
代码实现
cpp
class Solution {
public:
int maxProfit(int k, vector<int>& prices) {
int n = prices.size();
vector<vector<int>> f(n, vector<int>(k + 1, 0));
vector<vector<int>> g(n, vector<int>(k + 1, 0));
for (int i = 1; i <= k; i++)
f[0][i] = g[0][i] = -0x3f3f3f;
f[0][0] = -prices[0];
g[0][0] = 0;
for (int i = 1; i < n; i++) {
for (int j = 0; j <= k; j++) {
f[i][j] = max(f[i - 1][j], g[i - 1][j] - prices[i]);
g[i][j] = g[i - 1][j];
if (j > 0)
g[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + prices[i]);
}
}
int ret = -0x3f3f3f;
for (int i = 0; i <= k; i++)
ret = max(ret, g[n - 1][i]);
return ret;
}
};
本篇文章到这里就结束了,感谢支持
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws