1. 问题背景与核心挑战
股票交易中的冷冻期限制是量化投资领域一个经典的问题变种。这个问题在LeetCode上编号为309,属于动态规划类问题的进阶题型。与常规股票买卖问题不同,冷冻期的加入使得状态转移逻辑更加复杂,需要更精细的状态划分和转移方程设计。
冷冻期规则具体指:在卖出股票后的第一天(即次日)不能立即买入股票,必须等待至少一天。这个限制条件直接影响了交易策略的连续性,使得传统的"持有/不持有"两状态模型无法满足需求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 状态机模型构建
2.1 三状态定义
解决这个问题的关键在于建立正确的状态转移模型。我们需要定义三个核心状态:
- 持有状态(hold):当前持有股票,可能是今天买入或之前买入
- 冷冻状态(cooldown):今天卖出股票,次日将进入冷冻期
- 可交易状态(ready):可以自由买入股票的状态
这种三状态划分完美捕捉了冷冻期限制下的所有可能情况。相比传统的两状态模型,增加的状态能够准确表达"卖出后必须等待"这一约束条件。
2.2 状态转移图
各状态间的转移关系如下:
- hold → hold:继续持有不操作
- hold → cooldown:卖出持有的股票
- cooldown → ready:冷冻期结束
- ready → ready:继续保持观望
- ready → hold:买入股票
这种状态机模型确保了我们永远不会在卖出后的次日立即买入,完全符合题目要求的冷冻期限制。
3. 动态规划实现
3.1 DP数组定义
我们使用三个一维数组来分别记录每天结束时处于各状态的最大收益:
python复制hold = [0] * n # 第i天结束时持有股票的最大收益
cooldown = [0] * n # 第i天结束时处于冷冻期的最大收益
ready = [0] * n # 第i天结束时可以交易的最大收益
3.2 初始化条件
第一天(i=0)的特殊情况:
python复制hold[0] = -prices[0] # 买入股票
cooldown[0] = -inf # 不可能第一天就卖出
ready[0] = 0 # 不操作
3.3 状态转移方程
对于第i天(i>0)的状态转移:
python复制# 保持持有或从ready状态买入
hold[i] = max(hold[i-1], ready[i-1] - prices[i])
# 只能从hold状态卖出转移而来
cooldown[i] = hold[i-1] + prices[i]
# 保持ready或从cooldown转移而来
ready[i] = max(ready[i-1], cooldown[i-1])
3.4 最终结果
最大收益出现在最后一天处于ready或cooldown状态:
python复制max(ready[-1], cooldown[-1])
4. 空间优化技巧
原始实现使用了O(n)的空间复杂度,但实际上我们只需要前一天的三个状态值即可计算当前状态。因此可以优化到O(1)空间:
python复制def maxProfit(prices):
if not prices:
return 0
hold = -prices[0]
cooldown = -float('inf')
ready = 0
for price in prices[1:]:
prev_hold, prev_cooldown, prev_ready = hold, cooldown, ready
hold = max(prev_hold, prev_ready - price)
cooldown = prev_hold + price
ready = max(prev_ready, prev_cooldown)
return max(ready, cooldown)
5. 实际应用中的变种
5.1 交易手续费
如果加入每次交易固定手续费fee,只需修改cooldown和hold的转移方程:
python复制cooldown[i] = hold[i-1] + prices[i] - fee
hold[i] = max(hold[i-1], ready[i-1] - prices[i] - fee)
5.2 多次交易限制
对于最多k次交易的限制,需要增加一维表示交易次数:
python复制dp[k][i][state]
状态转移会变得更加复杂,但核心思路不变。
6. 调试与验证技巧
6.1 边界条件测试
需要特别测试的边界情况:
- 空价格序列
- 单日价格
- 连续下跌行情
- 连续上涨行情
6.2 状态跟踪法
在调试时可以打印每天的状态值表格:
code复制Day | Price | Hold | Cooldown | Ready
-------------------------------------
0 | 1 | -1 | -inf | 0
1 | 2 | -1 | 1 | 0
2 | 3 | -1 | 2 | 1
这样能直观验证状态转移是否正确。
7. 复杂度分析
- 时间复杂度:O(n),只需遍历价格序列一次
- 空间复杂度:
- 原始实现:O(n)
- 优化实现:O(1)
8. 与其他股票问题的对比
与121题(单次交易)和122题(无限次交易)相比,309题的状态设计:
- 需要区分"可以买入"和"不能买入"的状态
- 卖出操作会导致状态强制转移
- 收益计算需要考虑状态间的时序关系
这种状态机模型也可应用于其他具有类似限制条件的问题,如:
- 带等待期的资源分配
- 有冷却时间的任务调度
- 存在延迟约束的序列决策
