LeetCode123:買賣股票的最佳時機(jī) III

問題121:給定一個數(shù)組,它的第i個元素是給定股票第i天的價格。如果你最多只能買入和賣出兩次,設(shè)計一個算法來計算你所能獲取的最大利潤。注意:你不能在買入股票前賣出股票。

解法一:切成兩段,每段分別用第121題的方法,求兩段和最大值;

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        def maxPro(prices):
            if not prices:
                return 0
            dif = []
            predp = 0
            ans = 0
            for i in range(1, len(prices)):
                dif = prices[i] - prices[i-1]
                predp = max(dif, dif + predp)           
                ans = max(predp, ans)
            return ans
        
        max_pro = 0
        for mid in range(0, len(prices)):
            cur_pro = maxPro(prices[:mid+1]) + maxPro(prices[mid+1:])
            if cur_pro > max_pro:
                max_pro = cur_pr
        return max_pro

這種方法比較直觀,但是會超時。

解法二:動態(tài)規(guī)劃。

這種解法,比較難理解,也可能是我太菜了,自己從頭到尾推了一遍,才勉強(qiáng)理解。

舉個例子,對于[7, 1, 5, 3, 6, 4], 其狀態(tài)轉(zhuǎn)移圖如下所示。先遍歷列,再遍歷行。注意,輸出的是max(0, max(dp[len(prices)][2], dp[len(prices)][4])),因?yàn)樽畲罄麧櫦瓤赡茉诘谝淮钨u出時獲得,又可能在第二次賣出時獲得。如果操作一定虧損,干脆不進(jìn)行任何操作,直接輸出0

完整代碼:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [[float('-inf') for _ in range(5)] for _ in range(len(prices)+1)]
        for i in range(len(prices)+1):
            dp[i][0] = 0
        for i in range(1, len(prices)+1):
            for j in range(1, 5):          
                if j % 2 == 1:
                    dp[i][j] = max(dp[i-1][j-1] - prices[i-1], dp[i-1][j])
                else:
                    dp[i][j] = max(dp[i-1][j-1] + prices[i-1], dp[i-1][j])
        return max(0, max(dp[len(prices)][2], dp[len(prices)][4]))

運(yùn)行結(jié)果:

與背包問題類似,我們可以對該程序進(jìn)行優(yōu)化,優(yōu)化到一維。
注意,j要從后往前遍歷,因?yàn)橛嬎?img class="math-inline" src="https://math.jianshu.com/math?formula=dp%5Bj%5D" alt="dp[j]" mathimg="1">的時候,dp[j]的值依賴于dp[j-1],而此時的dp[j-1]應(yīng)該是第i-1輪的,而不是第i輪的。所以,一定要在更新dp[j-1]之前更新dp[j],因此j要從后往前遍歷。同時,這也是先遍歷i,再遍歷j的原因。

優(yōu)化代碼:

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [float('-inf') for _ in range(5)]
        dp[0] = 0        
        for i in range(1, len(prices)+1):
            #j從后往前遍歷
            for j in range(4, 0, -1):
                if j % 2 == 1:
                    dp[j] = max(dp[j-1] - prices[i-1], dp[j])
                else:
                    dp[j] = max(dp[j-1] + prices[i-1], dp[j])
        return max(0, max(dp[2], dp[4]))

運(yùn)行結(jié)果:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。