從狀態機看股票交易問題

概述

動態規劃的一種典型題型:
一般的動態規劃都是

 dp[n] = f(dp[x])

但是有一種題型的動態規劃的轉移方程是:

dp[n] = f(g[x]) 
g[x] = dp[x]

這種就是含狀態機的動態規劃問題

股票交易問題的通用解法:

  1. 定義動態數組:
    dp[i][k][0] 代表當前天是第i天,已經交易k次,現在不持有股票的最大利潤
    dp[i][k][1] 代表當前天是第i天,已經交易k次,現在持有股票的最大例如

  2. 初始化:
    初始化的方向主要有兩個原則:沒有交易的時候利潤爲0,不可能事件的利潤爲 -inf
    第0天,如果還沒持有股票,利潤爲0
    第0天,已經持有股票,利潤爲-price[0]

  3. 轉移方程

    # 賣出不消耗次數
    # 第i天,已經進行k次交易,並且不持有股票,我的值要不然就是前一天已經進行k次交易且不持有股票。要不就是前一天只進行k次交易並且持有股票,然後今天我把股票賣掉
    dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
    # 買入消耗次數
    # 第i天,已經進行k次交易,並且持有股票,我的值要不然就是前一天已經進行k次交易且持有股票。要不就是前一天只進行k-1次交易並且不持有股票,然後今天我把股票買回來
    dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])
    
  4. 循環區間

    for i in range(size):
        for k in range(max_K,0,-1): #k爲什是倒敘呢,不理解?[max_k,1]
        	pass
    
  5. 返回結果
    最後一天,交易了max_k次,並且不持有股票的利潤

    dp[-1][max_k][0]
    

題型:k爲有限次

k爲1次:121. 買賣股票的最佳時機

在這裏插入圖片描述

class Solution:
    def maxProfit(self, prices) -> int:
        max_K = 1
        size = len(prices)

        if size == 0:
            return 0

        # dp[i][k][j] i [0,size-1] k [0,max_K] j [0,1]
        dp = [[[0, 1] for _ in range(max_K + 1)] for _ in range(size)]

        for i in range(size):
            for k in range(max_K,0,-1):
                if i == 0:  # 初始化
                    dp[i][k][0] = 0
                    dp[i][k][1] = -prices[i]
                else:
                    dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
                    dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])

        return dp[size - 1][max_K][0]

k爲2次:123. 買賣股票的最佳時機 III

在這裏插入圖片描述

class Solution:
    def maxProfit(semaxlf, prices: List[int]) -> int:
        max_k = 2
        size = len(prices)
        dp = [[[0,0] for _ in range(max_k + 1)] for i in range(size)]

        if size == 0:
            return 0

        for i in range(size):
            for k in range(max_k, 0, -1):
                if i == 0:
                    dp[i][k][0] = 0
                    dp[i][k][1] = -prices[i]
                else:
                    dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
                    dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])

        return dp[size - 1][max_k][0]

k次交易:188. 買賣股票的最佳時機 IV

在這裏插入圖片描述

class Solution:
    def maxProfit(self, max_k: int, prices: List[int]) -> int:
        size = len(prices)

        if size == 0:
            return 0

        dp = [[[0,0] for i in range(max_k + 1)] for i in range(size)]

        for i in range(size):
            for k in range(max_k, 0, -1):
                if i == 0:
                    dp[i][k][0] = 0
                    dp[i][k][1] = -prices[i]
                else:
                    dp[i][k][0] = max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
                    dp[i][k][1] = max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])

        return dp[-1][max_k][0]

題型:k爲無限次

當k爲無限次的時候,k就不再有參考意義,k將退化成二維

  1. 定義dp
    dp[i][0] # 代表第i天不持有股票
    dp[i][1] # 代表第i天持有股票

  2. 初始化

    當i爲0時:

    dp[i][0 = 0
    dp[i][1] = -price[0]
    
  3. 轉移方程

    dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i])
    dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i])
    

k爲無限次:122. 買賣股票的最佳時機 II

在這裏插入圖片描述

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        size = len(prices)

        if size == 0:
            return 0

        dp = [[0,0] for _ in range(size)]


        for i in range(size):
            if i == 0:
                dp[i][0] = 0
                dp[i][1] = -prices[i]
            else:
                dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i])
                dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i])
                
        return dp[-1][0]

k爲無限次帶手續費:714. 買賣股票的最佳時機含手續費

在這裏插入圖片描述
根據示例可知,只是賣出的時候收手續費

class Solution:
    def maxProfit(self, prices,fee) -> int:
        size = len(prices)

        if size == 0:
            return 0

        dp = [[0,0] for _ in range(size)]


        for i in range(size):
            if i == 0:
                dp[i][0] = 0
                dp[i][1] = -prices[i]
            else:
                dp[i][0] = max(dp[i-1][0],dp[i-1][1]+prices[i]-fee) # 賣出的時候交手續費
                dp[i][1] = max(dp[i-1][1],dp[i-1][0] - prices[i])
                
        return dp[-1][0]

k爲無限次,帶冷凍期:309. 最佳買賣股票時機含冷凍期

在這裏插入圖片描述

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        size = len(prices)
        if size == 0:
            return 0

        dp = [[0,0] for _ in range(size)]

        for i in range(size):
            if i == 0:
                dp[i][0] = 0
                dp[i][1] = -prices[i]
            elif i == 1:
                dp[i][0] = max(0, prices[i]-prices[i-1]) #如果第二天沒有股票,要不第一天就沒有,要不就是第一天買了,第二天賣出
                dp[i][1] = max(-prices[i-1], -prices[i]) # 我在第二天擁有股票,要不就是第一天買入,要不是第二天買入
            else:
                dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] + prices[i])
                dp[i][1] = max(dp[i - 1][1], dp[i - 2][0] - prices[i])

        return dp[size - 1][0]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章