算法套路-leetcode股票问题

1 套路分析

1.1 简介

股票问题汇总:

以上题目分析

  • 第1题只允许1次交易,
  • 第2题不限制交易次数,
  • 第3题限制交易次数为2次,
  • 第4题是最泛化的形式,只允许k次交易。
  • 第5题加上cool down
  • 第6题加上transaction fee

1.2 框架

股票问题状态有三个维度,

  • 第一个是当前天数,
  • 第二个是到当前所能允许交易的最大次数,(第k次包括第k次买入和第k次卖出)
  • 第三个是当前手头股票的持有状态,我们用0代表当前手头没有股票,1代表当前手头已经持有股票。

我们每天都有三种选择:买入股票,卖出股票,和继续持有现有的股票不做操作,我们用buy、sell和rest分别对应这三种选择。

这时候,我们可以有一个粗糙的框架。

dp[i][j][k] 为三维动态规划数组,储存所获的利润
0 <= i <= n-1, i代表当天天数,n代表总的天数
1 <= k <= K, k代表当前天数下所能允许交易的最大次数,K代表总最大允许交易次数
j = 0 or 10代表手头不持有股票,1代表手头持有股票
例子:dp[2][3][1]代表今天是第二题,现在我手上持有股票,至今为止最多进行3次交易。
for i:
    for k:
        for j:
            dp[i][k][j] = max(buy, sell, rest)
return dp[n-1][K][0] 
最后返回的是最后一天,最多允许大K次交易,手头股票都卖完了能得到的多少利润

1.3 状态转移方程

今天结束不持有股票,可能是前一天就没持有,今天没操作,也可能是前一天持有但今天卖出。

d p [ i ] [ k ] [ 0 ] = m a x ( d p [ i − 1 ] [ k ] [ 0 ] , d p [ i − 1 ] [ k ] [ 1 ] + p r i c e s [ i ] ) dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]) dp[i][k][0]=max(dp[i1][k][0],dp[i1][k][1]+prices[i])

今天结束持有股票,可能是前一天就持有,今天没操作,也可能是前一天没持有但今天买入。注意理解下面公式中的 k − 1 k-1 k1,买入+卖出是一对,因为前一天是卖出,所以前一天是第k-1次,今天是第k次。

d p [ i ] [ k ] [ 1 ] = m a x ( d p [ i − 1 ] [ k ] [ 1 ] , d p [ i − 1 ] [ k − 1 ] [ 0 ] − p r i c e s [ i ] ) dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]) dp[i][k][1]=max(dp[i1][k][1],dp[i1][k1][0]prices[i])

1.4 初始状态

dp=[[[0,-float('inf')] for i in range(k+1)] for j in range(n)]
#dp数组的形状是(n,k+1,2)

得益于python数组可以用index=-1代表数组最后一个元素,所以使用dp[0-1]不会出错,本来第一维应该长度应该为n+1,但我们直接拿数组最后一个元素作为第0天的前一天,反正数组的最后一个元素一开始肯定用不到,所以第一维长度为n,后面直接使用动态转移方程即可。

现在我们开始解题了。

2 解题

2.1 第1题,k=1

121. 买卖股票的最佳时机

因为k=1,所以去掉中间k这一维。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n=len(prices)
        if n<2:return 0
        dp=[[0,-float('inf')] for i in range(n)]#dp[i][0]代表第i天,手里没股票的最大利润
        dp[0][1]=-prices[0]
        for i in range(1,n):
            dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i])
            dp[i][1]=max(dp[i-1][1],-prices[i])
        return dp[n-1][0]

2.2 第2题,k=无穷

122. 买卖股票的最佳时机 II

因为k=无穷,所以也可以去掉k这一维。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n=len(prices)
        dp=[[0,-float('inf')] for i in range(n)]
        dp[0][1]=-prices[0]
        for i in range(n):
            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[n-1][0]

2.3 第3题,k=2

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

现在可以使用k这一维了。

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

2.4 第4题,k为任何整数

188. 买卖股票的最佳时机 IV

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

2.5 第5题,k为inf,有1天冷冻期

309. 最佳买卖股票时机含冷冻期

1天冷冻期,只需把dp[i][1]转移公式改为

d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 2 ] [ 0 ] − p r i c e s [ i ] ) dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]) dp[i][1]=max(dp[i1][1],dp[i2][0]prices[i])

即可。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n=len(prices)
        if n<2:return 0
        dp=[[0,-float('inf')] for i in range(n)]
        for i in range(n):
            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[n-1][0]

2.6 第6题,k为inf,有手续费

714. 买卖股票的最佳时机含手续费

只需把手续费从利润中扣去即可

class Solution:
    def maxProfit(self, prices: List[int], fee: int) -> int:
        n=len(prices)
        if n<2:return 0
        dp=[[0,-float('inf')] for i in range(n)]
        for i in range(n):
            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]-fee)#还是只变动了这一行
        return dp[n-1][0]

2.7 总结

以上的解答是不是都非常相似,只需记住第4题的万能模板,其他股票问题都可以从第4题演变出来。以上展示了各个股票问题的解答模板,大家也可以在模板基础上做优化,这就不在本文讨论里了。

参考文献

秒杀面试中的股票问题-看这一篇就够了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值