123.买卖股票的最佳时机III
文章讲解:https://programmercarl.com/0123.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAIII.html
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/
视频讲解:https://www.bilibili.com/video/BV1WG411K7AR/
动态规划五步骤、使用持有和不持有来计算。
因为最多有2次交持有和不持有,分了5种情况。
0.没有操作
1.第一次持有股票
2.第一次不持有股票
3.第二次持有股票
4.第二次不持有股票
dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
看过代码随想录后自己实现了一下,ac了。
public int maxProfit(int[] prices) {
// 确定dp数组以及下标含义:
// 持有和不持有,分了5种情况。
// 0. 没有操作
// 1. 第一次持有股票
// 2. 第一次不持有股票
// 3. 第二次持有股票
// 4. 第二次不持有股票
// dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
int[][] dp = new int[prices.length][5];
// 确定递推公式
// dp[i][0]可以忽略 都没有操作 = 0
// dp[i][1]第一次持有,可能是之前持有,可能是本次持有 dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
// dp[i][2]第一次不持有,可能是之前不持有,可能是本次不持有(本次不持有要上次持有的最大值+本次卖出) dp[i][2] = Math.max(dp[i-1][2],dp[i-1][1] + prices[i]);
// 确定初始化值
dp[0][0] = 0;
dp[0][1] -= prices[0];
dp[0][2] = 0;
dp[0][3] -= prices[0];
dp[0][4] = 0;
// 确定遍历顺序,从小打大
for(int i = 1; i < prices.length; i++){
dp[i][0] = dp[0][0];
// 第一次持有
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
// 第一次不持有,在最大的第一次持有上
dp[i][2] = Math.max(dp[i-1][2],dp[i-1][1] + prices[i]);
// 第二次持有,在最大的第一次不持有上计算
dp[i][3] = Math.max(dp[i-1][3],dp[i-1][2] - prices[i]);
// 第二次不持有,在上一次最大持有上计算
dp[i][4] = Math.max(dp[i-1][4],dp[i-1][3] + prices[i]);
}
return dp[prices.length - 1][4];
}
188.买卖股票的最佳时机IV
文章讲解:https://programmercarl.com/0188.%E4%B9%B0%E5%8D%96%E8%82%A1%E7%A5%A8%E7%9A%84%E6%9C%80%E4%BD%B3%E6%97%B6%E6%9C%BAIV.html
题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/
视频讲解:https://www.bilibili.com/video/BV16M411U7XJ/
和123.买卖股票的最佳时机III几乎一样,只是买具体买卖的次数用k来替换。
写代码的话就将k之前的情况分成2k+1种:
0. 没有操作
1.第一次持有股票
2.第一次不持有股票
3…第k次持有
4…第k次不持有
代码就把最佳时机III改吧改吧。
public int maxProfit(int k, int[] prices) {
// 确定dp数组以及下标含义:
// 持有和不持有,分了5种情况。
// 0.没有操作
// 1.第一次持有股票
// 2.第一次不持有股票
// 3......第k次持有
// 4......第k次不持有
// dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最大现金。
int[][] dp = new int[prices.length][2*k + 1];
// 确定初始化值
for(int i = 0; i < 2*k + 1; i++){
if(i % 2 == 1){
dp[0][i] -= prices[0];
}else{
dp[0][i] = 0;
}
}
// 确定遍历顺序,从小打大
for(int i = 1; i < prices.length; i++){
for(int j = 1; j < 2*k + 1; j++){
if(j % 2 == 0){
// 表示第j次不持有
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j - 1] + prices[i]);
}else{
// 表示第j次持有
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-1] - prices[i]);
}
}
}
return dp[prices.length - 1][2*k];
}
照着上一题改吧改吧完成。
对于股票问题有了进一步的认识,股票问题核心是理解第i天的持有状态,通过持有状态去推导最优值。