从状态机看股票交易问题

概述

动态规划的一种典型题型:
一般的动态规划都是

 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]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章