状态机 DP
2025年3月2日大约 5 分钟
状态机 DP
一般定义 f[i][j] 表示前缀 a[:i] 在状态 j 下的最优值。一般 j 都很小。代表题目是「买卖股票」系列。
| 题目 | 难度 | |
|---|---|---|
| 122. 买卖股票的最佳时机 II | 中等 | 不限交易次数 |
| 309. 买卖股票的最佳时机含冷冻期 | 中等 | dfs(n-2) |
| 714. 买卖股票的最佳时机含手续费 | 中等 | +fee |
| 188. 买卖股票的最佳时机 IV | 困难 | 至多交易 k 次 |
| 121. 买卖股票的最佳时机 | 简单 | k=1 |
| 123. 买卖股票的最佳时机 III | 困难 | k=2 |

122. 买卖股票的最佳时机 II
import java.util.Arrays; public class Solution122 { private int[] prices; private int[][] memo; public int maxProfit(int[] prices) { this.prices = prices; int n = prices.length; memo = new int[n][2]; for (int i = 0; i < n; i++) { Arrays.fill(memo[i], -1); } return dfs(n - 1, 0); } // dfs(i, 0) 表示到第 i 天结束时,未持有股票的最大利润 // dfs(i, 1) 表示到第 i 天结束时,持有股票的最大利润 // 第 i-1 天结束就是第 i 天的开始 private int dfs(int i, int hold) { if (i < 0) { if (hold == 1) return (int) -1e9; return 0; } if (memo[i][hold] != -1) return memo[i][hold]; int res; if (hold == 1) res = Math.max(dfs(i - 1, 1), dfs(i - 1, 0) - prices[i]); else res = Math.max(dfs(i - 1, 0), dfs(i - 1, 1) + prices[i]); return memo[i][hold] = res; } }309. 买卖股票的最佳时机含冷冻期
import java.util.Arrays; public class Solution309 { private int[] prices; private int[][] memo; public int maxProfit(int[] prices) { this.prices = prices; int n = prices.length; memo = new int[n][2]; for (int i = 0; i < n; i++) { Arrays.fill(memo[i], -1); } return dfs(n - 1, 0); } private int dfs(int i, int hold) { if (i < 0) { if (hold == 1) return (int) -1e9; return 0; } if (memo[i][hold] != -1) return memo[i][hold]; int res; if (hold == 1) res = Math.max(dfs(i - 1, 1), dfs(i - 2, 0) - prices[i]); else res = Math.max(dfs(i - 1, 0), dfs(i - 1, 1) + prices[i]); return memo[i][hold] = res; } }714. 买卖股票的最佳时机含手续费
import java.util.Arrays; public class Solution714 { private int[] prices; private int fee; private int[][] memo; public int maxProfit(int[] prices, int fee) { this.prices = prices; this.fee = fee; int n = prices.length; memo = new int[n][2]; for (int i = 0; i < n; i++) { Arrays.fill(memo[i], -1); } return dfs(n - 1, 0); } private int dfs(int i, int hold) { if (i < 0) { if (hold == 1) return (int) -1e9; return 0; } if (memo[i][hold] != -1) return memo[i][hold]; int res; if (hold == 1) res = Math.max(dfs(i - 1, 1), dfs(i - 1, 0) - prices[i] - fee); else res = Math.max(dfs(i - 1, 0), dfs(i - 1, 1) + prices[i]); return memo[i][hold] = res; } }188. 买卖股票的最佳时机 IV
import java.util.Arrays; public class Solution188 { private int[] prices; private int[][][] memo; public int maxProfit(int k, int[] prices) { this.prices = prices; int n = prices.length; memo = new int[n][k + 1][2]; for (int i = 0; i < n; i++) { for (int j = 0; j < k + 1; j++) { Arrays.fill(memo[i][j], -1); } } return dfs(n - 1, k, 0); } // dfs(i, 0) 表示到第 i 天结束时完成至多 j 笔交易,未持有股票的最大利润 // dfs(i, 1) 表示到第 i 天结束时完成至多 j 笔交易,持有股票的最大利润 // 第 i-1 天结束就是第 i 天的开始 private int dfs(int i, int j, int hold) { if (j < 0) return (int) -1e9; if (i < 0) { if (hold == 1) return (int) -1e9; return 0; } if (memo[i][j][hold] != -1) return memo[i][j][hold]; int res; if (hold == 1) res = Math.max(dfs(i - 1, j, 1), dfs(i - 1, j - 1, 0) - prices[i]); else res = Math.max(dfs(i - 1, j, 0), dfs(i - 1, j, 1) + prices[i]); return memo[i][j][hold] = res; } }(全文完)