学习目标:
动态规划五部曲:
① 确定dp[i]的含义
② 求递推公式
③ dp数组如何初始化
④ 确定遍历顺序
⑤ 打印递归数组 ---- 调试
引用自代码随想录!
60天训练营打卡计划!
学习内容:
188.买卖股票最佳时机4
- 只能至多买卖k次且不能同时参与多笔交易。
- 动态规划五步曲:
① 确定dp[i]的含义 :
第 i 天 不操作 的最大金额dp[i][0],
第 i天 第一次持有 这个股票的最大金额dp[i][1],
第 i 天 第一次不持有 这个股票的最大金额dp[i][2],
第 i 天 第k次持有 这个股票的最大金额dp[i][2k-1],
第 i 天 第k次不持有 这个股票的最大金额dp[i][2k]。
② 求递推公式 :
dp[i][0] = dp[i-1][0] ----- 为0
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - price[i])
dp[i][2] = max(dp[i-1][2], dp[i-1][1] + price[i])
dp[i][2k-1] = max(dp[i-1][2k-1], dp[i-1][2k-2] - price[i])
dp[i][2k] = max(dp[i-1][2k], dp[i-1][2k-1] + price[i])
③ dp数组如何初始化 : dp[0][0] = 0 dp[0][1] = -price[0] dp[0][2] = 0
dp[0][2k-1] = -price[0] dp[0][2k] = 0
④ 确定遍历顺序 : 从前向后
class Solution {
public int maxProfit(int k, int[] prices) {
int size = prices.length;
// 使用 2k+1 是为了统一递推关系式
int[][] dp = new int[size][2*k+1];
// 初始化
dp[0][0] = 0;
for(int j = 1; j <= 2*k-1; j=j+2){
dp[0][j] = -prices[0];
dp[0][j+1] = 0;
}
// 循环逻辑
// i是物品的数量
for(int i = 1; i < size; i++){
// j是买卖的次数
for(int j = 1; j <= 2*k-1; j=j+2){
// 买入
dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-1] - prices[i]);
// 卖出
dp[i][j+1] = Math.max(dp[i-1][j+1], dp[i-1][j] + prices[i]);
}
}
return dp[size-1][2*k];
}
}
309.买卖股票的最佳时机含冷冻期
- 在满足 卖出股票后,你无法在第二天买入股票 的条件下,你可以尽可能地完成更多的交易。
- 动态规划五步曲:
① 确定dp[i][j]的含义 :
第i天持有这个股票的最大金额dp[i][0],
第i个天保持卖出这个股票的最大金额dp[i][1],(买的时候没有冷冻期)
第i天卖出这个股票的最大金额dp[i][2],
第i个天冷冻期时这个股票的最大金额dp[i][3];
② 求递推公式 : - 持有状态:
- 一直持有 / 第 i-1 天保持卖出,第i天买入 / 第 i-1 天冷冻期,第i天买入 三者取最大
dp[i][0] = max(dp[i-1][0], max(dp[i-1][1]-price[i], dp[i-1][3]-price[i])) - 保持卖出:
- 第 i-1 天保持卖出 / 第 i-1 天冷冻期 取最大
dp[i][1] = max(dp[i-1][1], dp[i-1][3]) - 卖出:
- 第 i-1 天持有
dp[i][2] = dp[i-1][0] + price[i] - 冷冻期:
- 第 i-1 天卖出
dp[i][3] = dp[i-1][2]
③ dp数组如何初始化 :
dp[0][0] = -price[0]
以下都是非法状态: — 可以通过递推关系回推:
dp[0][1] = 0 dp[0][2] = 0 dp[0][1] = 0
④ 确定遍历顺序 : 从前向后
class Solution {
public int maxProfit(int[] prices) {
int size = prices.length;
int[][] dp = new int[size][4];
// 初始化
dp[0][0] = -prices[0];
// 以下都是非法状态,可以通过递推关系回推:
dp[0][1] = 0;
dp[0][2] = 0;
dp[0][3] = 0;
for(int i = 1; i < size; i++){
// 持有状态的递归推导
dp[i][0] = Math.max(dp[i-1][0],
Math.max(dp[i-1][1]-prices[i], dp[i-1][3]-prices[i]));
// 保持持有状态的递归推导
dp[i][1] = Math.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 Math.max(dp[size-1][1], Math.max(dp[size-1][2], dp[size-1][3]));
}
}
714.买卖股票的最佳时机含手续费
- 要使用尽量少的交易次数获得最大利润
- 动态规划五步曲:
① 确定dp[i][j]的含义 :
第i天持有这个股票的最大金额dp[i][0],第i个天不持有这个股票的最大金额dp[i][1];
第i-1天持有这个股票的最大金额dp[i-1][0],第i-1个天不持有这个股票的最大金额dp[i-1][1]。
② 求递推公式 : - 一直持有 / (第i-1必须未持有)第i天买入 取最大
dp[i][0] = max(dp[i-1][0],dp[i-1][1] - price[i]) - 一直未持有 / (第i-1必须持有)第i天卖出 取最大 , 其中fee指交易费
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+price[i] - fee)
③ dp数组如何初始化 : dp[0][0] = -price[0] dp[0][1] = 0
④ 确定遍历顺序 : 从前向后
class Solution {
public int maxProfit(int[] prices, int fee) {
int size = prices.length;
int[][] dp = new int[size][2];
// 初始化
dp[0][0] = -prices[0];
dp[0][1] = 0;
// 递归逻辑
for(int i = 1; i < size; i++){
dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] - prices[i]);
dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] + prices[i] - fee);
}
return dp[size-1][1];
}
}
学习时间:
- 上午两个半小时,整理文档半小时。