Leetcode 309. 最佳买卖股票时机含冷冻期
1 题目描述(Leetcode题目链接)
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
- 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
- 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
2 题解
本题是动态规划问题,根据问题描述,我们可以定义三个状态:
- 到第 i i i天为止,最后一次操作是买入,用 b u y [ i ] buy[i] buy[i]表示;
- 到第 i i i天为止,最后一次操作是卖出,用 s e l l [ i ] sell[i] sell[i]表示;
- 到第 i i i天为止,最后一次操作是冷冻期,用 c o o l [ i ] cool[i] cool[i]表示;
那么显然最终答案应该是
s
e
l
l
[
−
1
]
sell[-1]
sell[−1],下面来看状态转移方程。
对于
b
u
y
[
i
]
buy[i]
buy[i]来说,它可能为前一天就是买入今天仍是买入,还有可能前一天是冷冻期今天买入,所以:
b
u
y
[
i
]
=
m
a
x
(
b
u
y
[
i
−
1
]
,
c
o
o
l
[
i
−
1
]
−
p
r
i
c
e
s
[
i
]
)
buy[i] = max(buy[i-1], cool[i-1] - prices[i])
buy[i]=max(buy[i−1],cool[i−1]−prices[i])
对于
s
e
l
l
[
i
]
sell[i]
sell[i]来说,它可能为前一天就是卖出今天仍是卖出,还有可能前一天是买入今天卖出,所以:
s
e
l
l
[
i
]
=
m
a
x
(
s
e
l
l
[
i
−
1
]
,
b
u
y
[
i
−
1
]
+
p
r
i
c
e
s
[
i
]
)
sell[i] = max(sell[i-1], buy[i-1] + prices[i])
sell[i]=max(sell[i−1],buy[i−1]+prices[i])
对于
c
o
o
l
[
i
]
cool[i]
cool[i]来说,它只可能是前一天卖出,所以:
c
o
o
l
[
i
]
=
s
e
l
l
[
i
−
1
]
cool[i] = sell[i-1]
cool[i]=sell[i−1]
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices:
return 0
length = len(prices)
buy = [0]*length #最后操作是买能得到的最大钱
sell = [0]*length #最后操作是卖能得到的最大钱
cool = [0]*length #最后操作是冷冻期能得到的最大钱
buy[0] = -prices[0]
for i in range(1, length):
buy[i] = max(buy[i - 1], cool[i - 1] - prices[i])
sell[i] = max(sell[i - 1], buy[i - 1] + prices[i])
cool[i] = sell[i - 1]
return sell[-1]
观察上面的冷冻期,其实并不必要记录冷冻期的钱数,只需要记录最后一次是买或卖两种情况就好了。
对于
b
u
y
[
i
]
buy[i]
buy[i]来说,可能昨天就是买入今天还是买入状态,或者是前天卖掉了今天再买入,所以:
b
u
y
[
i
]
=
m
a
x
(
b
u
y
[
i
−
1
]
,
s
e
l
l
[
i
−
2
]
−
p
r
i
c
e
s
[
i
]
)
buy[i] = max(buy[i-1], sell[i-2] - prices[i])
buy[i]=max(buy[i−1],sell[i−2]−prices[i])
对于
s
e
l
l
[
i
]
sell[i]
sell[i]来说,可能昨天是卖出今天还是卖出状态,或者是昨天买入今天卖出,所以:
s
e
l
l
[
i
]
=
m
a
x
(
s
e
l
l
[
i
−
1
]
,
b
u
y
[
i
−
1
]
+
p
r
i
c
e
s
[
i
]
)
sell[i] = max(sell[i-1], buy[i-1] + prices[i])
sell[i]=max(sell[i−1],buy[i−1]+prices[i])
class Solution:
def maxProfit(self, prices: List[int]) -> int:
length = len(prices)
if length <= 1:
return 0
buy = [0]*length #到今天是买
sell = [0]*length #到今天是卖
buy[0], buy[1] = -prices[0], max(-prices[0], -prices[1])
sell[0], sell[1] = 0, max(0, prices[1] - prices[0])
for i in range(2, length):
buy[i] = max(buy[i-1], sell[i-2] - prices[i])
sell[i] = max(sell[i-1], buy[i-1] + prices[i])
return sell[-1]
其实还可以优化空间,用变量记录上一个值这样就能达到常数空间复杂度。