123. 买卖股票的最佳时机 III
前言
链接: 题目连接与题解.
一、题目?
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例1
输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,
这笔交易所能获得利润 = 3-0 = 3 。
随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,
这笔交易所能获得利润 = 4-1 = 3 。
示例2
输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出,
这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例3
输入:prices = [7,6,4,3,1]
输出:0
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。
二、思路与算法
1.动态规划
由于我们最多可以完成两笔交易,因此在任意一天结束之后,我们会处于以下五个状态中的一种:
-
未进行过任何操作;
-
buy1-----只进行过一次买操作;
-
sell1-----进行了一次买操作和一次卖操作,即完成了一笔交易;
-
buy2-----在完成了一笔交易的前提下,进行了第二次买操作;
-
sell2-----完成了全部两笔交易。
未进行任何操作的利润为0
,不必记录。剩下四个,分别将最大利润记为buy1,sell1,buy2,sell2。
那么,知道了第i-1
天结束后的四个状态,如何通过状态转移方程得到第 ii 天结束后的这四个状态呢?
buy1:
-
第
i
天不进行任何操作,保持不变。 -
在未进行任何操作的前提下以
prices[i]
的价格买入股票。buy1的状态转移方程: b u y 1 = m a x { b u y 1 ′ , − p r i c e s [ i ] } buy_1= max\left\{buy^{'}_{1}, - prices[i]\right\} buy1=max{ buy1′,−prices[i]}
buy’1是第
i-1
天的状态, 与第i
的天buy1做区分
sell1:
-
第
i
天不进行任何操作,保持不变。 -
只进行过一次买操作的前提下以
prices[i]
的价格卖出股票。sell1的状态转移: s e l l 1 = m a x { s e l l 1 ′ , b u y 1 ′ + p r i c e s [ i ] } sell_1= max\left\{sell^{'}_{1}, buy^{'}_{1}+ prices[i]\right\} sell1=max{ sell1′,buy1′+prices[i]}
同理
buy2状态转移方程: b u y 2 = m a x { b u y 2 ′ , s e l l 1 ′ − p r i c e s [ i ] } buy_2= max\left\{buy^{'}_{2}, sell^{'}_{1}- prices[i]\right\} buy2=max{ buy2′,sell1′−prices[i]}
sell2状态转移方程: s e l l 2 = m a x { s e l l 2 ′ , b u y 2 ′ + p r i c e s [ i ] } sell_2= max\left\{sell^{'}_{2}, buy^{'}_{2}+ prices[i]\right\} sell2=max{ sell2′,buy2′+prices[i]}
注意,在考虑边界条件,存在事实
在同一天买入并且卖出
, 不影响当天利润,没有收益
所有,状态转移可以写成:
{ b u y 1 = m a x { b u y 1 , − p r i c e s [ i ] } , s e l l 1 = m a x { s e l l 1 , b u y 1 + p r i c e s [ i ] } , b u y 2 = m a x { b u y 2 , s e l l 1 − p r i c e s [ i ] } , s e l l 2 = m a x { s e l l 2 , b u y 2 + p r i c e s [ i ] } . \left\{ \begin{aligned} buy_1= max\left\{buy_{1}, - prices[i]\right\}, \\ sell_1= max\left\{sell_{1}, buy_{1}+ prices[i]\right\}, \\ buy_2= max\left\{buy_{2}, sell_{1}- prices[i]\right\}, \\ sell_2= max\left\{sell_{2}, buy_{2}+ prices[i]\right\}. \\ \end{aligned} \right. ⎩⎪⎪⎪⎪⎨⎪⎪⎪⎪⎧buy1=max{
buy1,−prices[i]},sell1=max{
sell1,buy1+prices[i]},buy2=max{
buy2,sell1−prices[i]},sell2=max{
sell2,buy2+prices[i]}.
这里详细解释为什么在上面去除了上标:
-
对于买操作,
buy1, buy2
: 对前一天不进行操作buy1 = buy’1, buy2 = buy’2 。 -
对于卖操作,
sell1, sell2
: 对前一天不进行操作, 相当于在第i
天买入又卖出,sell1 = sell’1 - prices[i] + prices[i] = sell’1
那么边界的起始条件,在第i天,
-
buy1 = -prices[0]
-
sell1 = buy1 = -prices[0] = 0
-
buy2 = -prices[0]
-
sell2 = buy2 = -prices[0] = 0
从i=1
开始进行动态规划,由题求出进行不超过两笔交易的最大值,则最终答案在0,sell1,sell2的最大值。
边界条件中,sell1=sell2, 且维护最大值,故sell1=sell2 > 0。 且若进行一次就可以获得最大值,可放宽看做最后一天买入又卖出进行了两次交易,故最终返回sell2 。
2.代码题解
代码如下(示例):
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
buy1 = buy2 = -prices[0]
sell1 = sell2 = 0
for i in range(1, n):
buy1 = max(buy1, -prices[i])
sell1 = max(sell1, buy1 + prices[i])
buy2 = max(buy2, sell1 - prices[i])
sell2 = max(sell2, buy2 + prices[i])
return sell2