动态规划--股票总结

发布时间 2023-11-21 17:16:10作者: Frommoon

题目

  • 给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
    设计一个算法来计算你所能获取的最大利润。你最多可以完成 K笔 交易。
    注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

分析:

状态:天数i、允许交易的最大次数k、当前持有中状态(0/1)
选择:买入、卖出、无操作

通用模板

def maxProfit(self, prices: List[int]) -> int:
    n = len(prices)
    # 初始化动态规划数组
    dp = [[[0] * 2 for _ in range(3)] for _ in range(n)]
    #base case:
    dp[0][k][0]=0  # 第一天不持有股票,利润为0
    dp[0][k][1]=-prices[0]  # 第一天持有股票,利润为-buy
    #状态转移方程:
    for i in range (1,n):
        for k in range (1,K)
            # 不持有股票的情况,取前一天也不持有股票和前一天持有股票但今天卖出的最大利润
            dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]) 
            # 持有股票的情况,取前一天也持有股票和前一天不持有股票但今天买入的最大利润,交易次数k减一
            dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]) 
        return dp[n-1][K][0]
  • 当交易次数k为1(121题)或无穷(122题)时,k对状态转移没有影响,去掉k,从三维数组变成二维数组
def maxProfit(self, prices: List[int]) -> int:
    n = len(prices)
    # 初始化动态规划数组
    dp=[[0] * 2 for _ in range(n)]
    #base case:
    dp[0][0]=0  # 第一天不持有股票,利润为0
    dp[0][1]=-prices[0]  # 第一天持有股票,利润为-buy
    #状态转移方程:
    for i in range (1,n):
        # 不持有股票的情况,取前一天也不持有股票和前一天持有股票但今天卖出的最大利润
        dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]) 
        # 持有股票的情况,取前一天也持有股票和前一天不持有股票但今天买入的最大利润,交易次数k减一
        dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i]) #当k=1时dp[i-1][0][0]=0带入
    return dp[n-1][0]
  • 309题,k为无穷,含冷冻期,只需要在第i天选择买入的时候,从i-2的状态转移,而不是i-1
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]) 
  • 714题,含手续费,只需要在买入或者卖出的时候减去手续费即可
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-2][0] - prices[i]) 

优化

  • 目前上文提到的四个题,优化思路一致:用两个变量代替二维数组(持有/不持有)
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        #base case
        a=0   # 第一天不持有股票,利润为0
        b=-prices[0]   # 第一天持有股票,利润为-buy
        #动态转移
        for i in range(1,n):  #前面处理了第一天的情况,直接从第二天开始,可以避免下标越界的发生
            a=max(a,b+prices[i])    # 不持有股票的情况,取前一天也不持有股票和前一天持有股票但今天卖出的最大利润
            b=max(b,a-prices[i])    # 持有股票的情况,取前一天也持有股票和前一天不持有股票但今天买入的最大利润
        return a    # 最后一天不持有股票的利润即为最大利润

详细改动请见对应文章

  • 当交易次数k为2(123题)或任意给定值(188题)时
  • 此时k影响状态转移,不能省去,用三维数组。k=2时较小直接把所有情况列举,k为任意值时用for循环
    详情见之前文章