151. 买卖股票的最佳时机 III

151. 买卖股票的最佳时机 III

中文English

假设你有一个数组,它的第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])
原文地址:https://www.cnblogs.com/yunxintryyoubest/p/13062817.html