给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
1、题目分析
有三个状态:买入、卖出、冷冻。这种题目很显然都是利用动态规划方程来做,f(i),表示第i天后的最大收益。可以有三个状态变化:
- 第i天后手持股票的最大收益dp[i][0]
- 第i天后,没有股票,处于冷冻期的最大收益dp[i][1]
- 第i天后,没有股票,也不在冷冻期的最大收益dp[i][2]
2、解题分析
- 初始化起始状态
- dp[i][0],dp[i][1],dp[i][2] = -prices[0],0,0
- 每个状态的动态转移方程
- dp[i][0] = max(dp[i-1][0],dp[i][2]-prices[i])
- dp[i][1] = dp[i-1][0]+prices[i]
- dp[i][2] = max(dp[i-1][2],dp[i-1][1])
- 最终结果
- max(dp[n-1][0],dp[n-1][1],dp[n-1][2])
- 但是由于最后一天持有股票是没有意义的,因此简化成max(dp[n-1][1],dp[n-1][2])
3、代码
class Solution:
def maxProfit(self, prices: List[int]) -> int:
#优化之前
if not prices:
return 0
n = len(prices)
# 表示第i天之后的累计收益
# f[i][0]: 要么就是i-1天的时候的收益,第i天啥都不做;要么就是i-1天手上没有股票,不在冷冻期,第i天买了股票了
# f[i][1]: 手上不持有股票,并且处于冷冻期中的累计最大收益
# i天以后就处于冷冻期就说明i天进行卖出的操作了,然后就直接相加就可以
# f[i][2]: 手上不持有股票,并且不在冷冻期中的累计最大收益
# i天以后没有股票的收益其实就是i-1天没有股票的收益和i-1天后冷冻期的收益。
#本来是res = max(f[i][0],f[i][1],f[i][2])
#但是很显然n-1天后也就是最后一天后手持股票是没啥意义的,所以就变成了res = max(f[i][1],f[i][2])
f = [[-prices[0], 0, 0]] + [[0] * 3 for _ in range(n - 1)]
for i in range(1, n):
f[i][0] = max(f[i - 1][0], f[i - 1][2] - prices[i])
f[i][1] = f[i - 1][0] + prices[i]
f[i][2] = max(f[i - 1][1], f[i - 1][2])
return max(f[n - 1][1], f[n - 1][2])
# 优化后
#因为f[i][0]只和f[i-1][0]有关系
#因为f[i][1]只和f[i-1][0]有关系
#因为f[i][2]只和f[i-1][2]和f[i-1][1]有关系
#所以只需要保存这三个状态量就可以了,空间复杂度就降低到O(1)
if not prices:
return 0
size = len(prices)
f0, f1, f2 = -prices[0], 0, 0
for i in range(1, size):
newf0 = max(f0, f2 - prices[i])
newf1 = f0 + prices[i]
newf2 = max(f1, f2)
f0, f1, f2 = newf0, newf1, newf2
return max(f1, f2)
总结 股票问题早有耳闻,虽然知道用动态规划的方法,但是就是写不出来。动态规划太灵活了。