151. 买卖股票的最佳时机 III
假设你有一个数组,它的第i个元素是一支给定的股票在第i天的价格。设计一个算法来找到最大的利润。你最多可以完成两笔交易。
样例
样例 1
输入 : [4,4,6,1,1,4,2,5]
输出 : 6
注意事项
你不可以同时参与多笔交易(你必须在再次购买前出售掉之前的股票)
思路:
一.确定状态
如果要求前n天(第n-1天)结束后,在阶段5的最大获利,设为f[n][5]。 总共就两种可能,要么是第n天刚好处于阶段5,(前一天是阶段4)
要么是第n天已经处于阶段5,(前一天已经是阶段5)
情况1:第n-2天就在阶段5 f[n][5]
情况2:第n-2天还在阶段4 (第二次持有股票) 第n-1天卖掉
f[n-1][4] + (Pn-1 - Pn-2)
如果要求前n天(第n-1天)结束后,再阶段4中的最大获利,设为f[n][4]
情况1:第n-2就在阶段4, f[n-1][4] + (Pn-1 - Pn-2)
情况2:第n-2天还在阶段3, f[n-1][3] (也可以说是后面加的是0,n天刚刚处于阶段4,获利0,刚刚买了,还没有获利)
子问题
要求f[n][1],...f[n][5]
需要知道f[n-1][1],...,f[n-1][5]
状态:
f[i][j]表示前i天(第i-1天)结束后,在阶段j的最大获利
二.转移方程:
阶段1,3,5, -- 手中无股票状态
f[i][j] = max(f[i-1][j],f[i-1][j-1] + Pi-1 - Pi-2)
昨天已经没有持有股票 昨天仍持有股票,当天刚好卖出股票,所以需要加上当天卖出的股票所获得的利
解析:
核心:上一天只有两种可能,要么是已经处于无股票状态,要么是仍然处于股票状态(则当天就需要卖出)
1.上一天已处于无股票状态:
f[i][j] = f[i-1][j]
2.上一天仍处于有股票状态,第i天刚好卖出,处于无股票状态.则获利是上一天的获利f[i-1][j-1] ,加上当天的获利 Pi-1 - Pi-2
f[i][j] = f[i-1][j-1] + (Pi-1 - Pi-2)
f[i][j]:前i天(第i-1天)结束后,处于阶段j的最大获利
阶段2,4 手中有股票状态
f[i][j] = max(f[i-1][j] + Pi-1 - Pi-2,f[i-1][j-1])
解析:手中有股票状态f[i][j]
也只有两种可能:
1.要么是上一天也持有股票,然后继续获利
f[i-1][j] + Pi-1 - Pi-2
2.要么是上一天已经没有股票,然后今天刚好买入,则今天不获利
f[i-1][j-1]
三.初始条件和边界情况:
刚开始(前0天)处于阶段1
f[0][1] = 0 不获利
f[0][2] = f[0][3] = f[0][4] =f[0][5] = -无穷
如果j-1 < 1或者i -2 < 0,对应项不计入max
注意:f[0][1] 0表示的第多少天,1表示的当前天处于第几阶段
因为最后买卖两次,所以答案是max(f[i][1],f[i][3],f[i][5)
最后一天肯定是处于1,3,5这几个阶段,清仓下最后一天最大获利
四.计算顺序:
f[0][1]...f[0][5]
f[1][1]...f[1][5]
...
f[n][1]...f[n][5]
class Solution: """ @param prices: Given an integer array @return: Maximum profit """ ''' 大致思路: 第i天可能处于5种状态,无股票,有股票,无股票,有股票,无股票 所以转化为子问题也就是 如果是第i天处于无股票状态: 1.上一天也是无股票:f[i-1][j] 2.上一天是有股票,第i天刚好无股票(刚好卖出):f[i-1][j-1] + Pi-1 - Pi-2 f[i][j] = max(f[i - 1][j],f[i-1][j-1] + Pi-1-Pi-2) 如果是第i天处于有股票状态 1.上一天处于有股票状态,当天仍然获利 f[i-1][j] + Pi-1 - Pi-2 2.上一天处于无股票状态,当天刚好买入股票:f[i-1][j] + 0 当天不获利 f[i][j] = max(f[i-1][j] + Pi-1 - Pi-2,f[i-1][j-1] + 0) ''' def maxProfit(self, prices): if not prices or len(prices) == 0:return 0 l = len(prices) f = [[-sys.maxsize]*6 for _ in range(l + 1)] #前0天什么都没有,只能是处于第一阶段,无股票,获利也是0 f[0][1] = 0 #计算顺序 for i in range(1,l + 1): #如果是处于无股票状态,1,3,5状态 for j in range(1,6,2): #第一天是不用判断,和上一天判断,后面才需要判断 f[i][j] = f[i - 1][j] ##必须保证j > 1,i >= 2,从第二天开始,且必须上一天不能是负无穷。填充的是1,3,5 当天无股票状态 if (j > 1) and (i >= 2) and (f[i - 1][j - 1] != -sys.maxsize):#如果上一个是-sys.maxsize 则说明是一个废的值,不符合要求,即不符合该状态(例如第一天第4阶段) f[i][j] = max(f[i][j],f[i - 1][j - 1] + prices[i - 1] - prices[i - 2]) #如果是当天处于有股票状态,2,4状态.填充的是2,4 当前天有股票状态 for j in range(2,6,2): f[i][j] = f[i - 1][j - 1] if (i >= 2) and (f[i - 1][j - 1] != -sys.maxsize): f[i][j] = max(f[i - 1][j] + prices[i - 1] - prices[i - 2],f[i][j]) return max(f[l][1],f[l][3],f[l][5])