题目解析
本题是经典的动态规划问题,要求我们在遵守以下股票交易规则的情况下,计算出最大化收益:
- 可以多次买卖股票;
- 买入之前必须先卖出手中持有的股票;
- 卖出后有一天冷冻期,在冷冻期内不能买入。
解题思路
1. 动态规划建模
设 dp[i][state] 表示第 i 天处于某个状态 state 时的最大收益,其中:
state = 0表示不持有股票且不在冷冻期;state = 1表示持有股票;state = 2表示不持有股票且在冷冻期。
状态转移方程
-
不持有股票且不在冷冻期:
- 第 i 天没有股票且不在冷冻期,可能是前一天也是这种状态,或者从冷冻期结束转换过来。
-
持有股票:
- 第 i 天持有股票,可能是前一天也持有股票,或者今天买入了股票(从状态 0 转移过来)。
-
不持有股票且在冷冻期:
- 第 i 天处于冷冻期,必然是前一天卖出了股票。
初始条件
- 第一天没有股票且不在冷冻期:dp[0][0] = 0;
- 第一天持有股票:(因为买入股票收益为负);
- 第一天不持有股票且在冷冻期:dp[0][2] = 0。
最终结果
最大收益出现在状态 0 或 2 中:
2. 时间和空间优化
由于 dp[i] 的状态只依赖于 dp[i-1],可以将 的空间复杂度优化为 。
算法实现
Python 代码
def max_profit(stocks):
if not stocks or len(stocks) < 2:
return 0
# 初始化状态变量
n = len(stocks)
hold = -stocks[0] # 持有股票的状态
no_stock = 0 # 不持有股票且不在冷冻期
frozen = 0 # 不持有股票且在冷冻期
# 动态规划过程
for i in range(1, n):
new_no_stock = max(no_stock, frozen) # 状态 0
new_hold = max(hold, no_stock - stocks[i]) # 状态 1
new_frozen = hold + stocks[i] # 状态 2
# 更新状态
no_stock, hold, frozen = new_no_stock, new_hold, new_frozen
# 返回最终结果
return max(no_stock, frozen)
# 测试样例
print(max_profit([1, 2])) # 输出: 1
print(max_profit([2, 1])) # 输出: 0
print(max_profit([1, 2, 3, 0, 2])) # 输出: 3
print(max_profit([2, 3, 4, 5, 6, 7])) # 输出: 5
print(max_profit([1, 6, 2, 7, 13, 2, 8])) # 输出: 12
示例解析
示例 1:
- 第 1 天买入,收益为 -1;
- 第 2 天卖出,收益为 2 - 1 = 1。
最终收益:11。
示例 3:
- 第 1 天买入,收益为 -1;
- 第 2 天卖出,收益为 2 - 1 = 1;
- 第 4 天买入,收益为 1 - 0 = 1;
- 第 5 天卖出,收益为 2 - 0 = 2。
最终收益:1 + 2 = 3。
复杂度分析
-
时间复杂度:O(n),其中 n 是股票价格的天数。
- 遍历股票价格一次,每天更新三个状态。
-
空间复杂度:O(1)。
- 使用常量级别的变量存储状态。
总结
本题通过动态规划解决,核心在于构建三种状态的转移方程并严格按照规则进行状态更新。这三种状态分别是:持有股票、不持有股票且不在冷冻期、不持有股票且在冷冻期。通过对状态转移方程的优化,我们能够有效减少不必要的重复计算。经过进一步优化,时间复杂度降低到 O(n)O(n),空间复杂度也优化为 O(1)O(1),仅需少量变量存储状态值,从而达到了理想的时间和空间效率。这是经典的股票交易问题之一,在动态规划领域具有很高的学习价值,同时也能很好地帮助我们理解复杂问题的分解与求解。