这道题是经典的动态规划(状态机)问题。核心在于处理“冷冻期”:卖出股票后,你无法在第二天买入股票(即冷冻期为 1 天)。
我们可以通过维护三个状态来解决这个问题。
思路解析
我们可以定义三种状态:
- 持有股票 (hold):当前手里有一支股票。
- 不持有股票,处于冷冻期 (cooldown):今天刚卖出股票,明天不能买。
- 不持有股票,不处于冷冻期 (free):手里没股票,且不是刚卖出的,可以随时买入。
状态转移方程:
- hold 的来源:
- 昨天就持有,今天休息:dp[i-1][hold]
- 昨天是“不持有且非冷冻期”,今天买入:dp[i-1][free] - prices[i]
- cooldown 的来源:
- 昨天持有,今天卖出:dp[i-1][hold] + prices[i]
- free 的来源:
- 昨天是冷冻期,今天解冻:dp[i-1][cooldown]
- 昨天就是“不持有且非冷冻期”,今天继续休息:dp[i-1][free]
Java 代码实现
为了节省空间,我们不需要维护整个二维数组,只需要用三个变量滚动更新即可。
class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length < 2) {
return 0;
}
// 初始化第一天的状态 // hold: 第一天买入,收益为 -prices[0] int hold = -prices[0]; // cooldown: 第一天不可能卖出,收益为 0 int cooldown = 0; // free: 第一天不操作,收益为 0 int free = 0; for (int i = 1; i < prices.length; i++) { // 保存上一轮的状态,防止计算过程中被覆盖 int prevHold = hold; int prevCooldown = cooldown; int prevFree = free; // 状态转移 // 1. 今天持有:要么昨天就持有,要么昨天是 free 状态今天买入 hold = Math.max(prevHold, prevFree - prices[i]); // 2. 今天冷冻:意味着昨天持有,今天卖出了 cooldown = prevHold + prices[i]; // 3. 今天 free:要么昨天是冷冻期今天解冻,要么昨天就是 free free = Math.max(prevCooldown, prevFree); } // 最后一天,手里没股票肯定比手里有股票赚得多(或者持平) // 所以取 cooldown 和 free 的最大值 return Math.max(cooldown, free); }}
复杂度分析
- 时间复杂度:O(N),只需要遍历一次价格数组。
- 空间复杂度:O(1),只使用了常数个变量来存储状态。
关键点总结
- 冷冻期的处理:买入时只能从 free 状态转移过来,不能从 cooldown 转移(因为 cooldown 的第二天必须继续休息,不能买入)。
- 最终结果:最后一天肯定是“不持有股票”的状态收益最高,所以答案是 max(cooldown, free)。
需要顺带看看它的变体 LeetCode 122(无冷冻期)的解法吗?对比着看状态机设计会更清晰。