好的,我们用 dp[i][0]
和 dp[i][1]
来分别表示第 i
天持有股票和不持有股票时的最大收益。我们来详细分析一下这种动态规划状态转移的方式。
动态规划定义
dp[i][0]
:表示在第i
天持有股票时的最大收益。dp[i][1]
:表示在第i
天不持有股票时的最大收益。
状态转移方程
-
对于
dp[i][0]
(第i
天持有股票):- 有两种情况:
- 昨天也持有股票:即
dp[i-1][0]
的状态继续到今天。 - 昨天没有股票,但今天买入了股票:那么今天的现金 = 昨天不持有股票的最大收益
dp[i-1][1]
减去今天买入股票的价格prices[i]
。
- 昨天也持有股票:即
- 状态转移方程:
[
dp[i][0] = \max(dp[i-1][0], dp[i-1][1] - prices[i])
]
- 有两种情况:
-
对于
dp[i][1]
(第i
天不持有股票):- 也有两种情况:
- 昨天就没有股票:即
dp[i-1][1]
的状态继续到今天。 - 昨天持有股票,但今天卖出了:那么今天的现金 = 昨天持有股票的最大收益
dp[i-1][0]
加上今天卖出股票的价格prices[i]
。
- 昨天就没有股票:即
- 状态转移方程:
[
dp[i][1] = \max(dp[i-1][1], dp[i-1][0] + prices[i])
]
- 也有两种情况:
初始条件
-
第0天持有股票时的最大收益
dp[0][0]
:- 由于还没有买入操作,设为
-prices[0]
,表示买入股票花费的钱。
[
dp[0][0] = -prices[0]
]
- 由于还没有买入操作,设为
-
第0天不持有股票时的最大收益
dp[0][1]
:- 还没有买卖操作,收益为
0
。
[
dp[0][1] = 0
]
- 还没有买卖操作,收益为
最终结果
整个数组遍历结束后,我们要找到最后一天不持有股票的最大收益 dp[n-1][1]
,因为这是利润最大化的状态。
代码实现
def maxProfit(prices):
if not prices:
return 0
n = len(prices)
dp = [[0] * 2 for _ in range(n)]
# 初始化
dp[0][0] = -prices[0] # 第0天持有股票的收益
dp[0][1] = 0 # 第0天不持有股票的收益
# 动态规划过程
for i in range(1, n):
# 第 i 天持有股票的情况
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i])
# 第 i 天不持有股票的情况
dp[i][1] = max(dp[i - 1][1], dp[i - 1][0] + prices[i])
# 最终答案为最后一天不持有股票的最大收益
return dp[-1][1]
例子讲解
以 prices = [7, 1, 5, 3, 6, 4]
为例,来展示 dp
数组的变化:
天数 | prices[i] | dp[i][0] (持有股票) | dp[i][1] (不持有股票) |
---|---|---|---|
0 | 7 | -7(买入股票) | 0 |
1 | 1 | -1(以更低价买入) | 0 |
2 | 5 | -1(前一天持有股票) | 4(今天卖出,利润 5-1=4) |
3 | 3 | -1(前一天持有股票) | 4(保持不持有状态) |
4 | 6 | -1(前一天持有股票) | 5(今天卖出,利润 6-1=5) |
5 | 4 | -1(前一天持有股票) | 5(保持不持有状态) |
- 在最后一天
dp[5][1] = 5
,即最大利润为 5。
总结
通过定义 dp[i][0]
和 dp[i][1]
,我们分别表示持有和不持有股票的最大收益,并且利用状态转移方程不断更新。这种动态规划的思路帮助我们在每一天都能做出最优决策,最终求得整个过程中的最大收益。