从买卖股票问题看状态转移方程

目录

121. 买卖股票的最佳时机

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

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

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

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

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


买卖股票的问题,本质上是一个动态规划的问题。

针对股票买卖这一问题,想获取某一天的最大利润,则在持有股票和卖出股票两种状态中,显然应该是卖出股票状态(即手上没有股票的状态)。

这里持有股票状态为1,卖出股票状态为0的话,则第n-1天,交易k次的利润为:

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

翻译成可以理解的语言为:一个人第n天在交易了k次后没有持有股票,则他可能是:
1.第(n-1)天就没有持有,然后第n天没有产生任何行为;
2.第(n-1)天持有股票,但是第n天卖出了股票。

从中选出最大值即为当前天的最大利润。

第n天持有股票时的最大利润为:

dp[n][k][1] = max(dp[n-1][k][1],dp[n-1][k-1][0]-prices[n])

翻译成可以理解的语言为:一个人第n天在交易了k次后持有股票,则他可能是:
1.第(n-1)天就持有,然后第n天没有产生任何行为;
2.第(n-1)天交易(k-1)次后没有持有股票,但是第n天买入了股票。

以上就是买卖股票的基本状态转移方程。不过为了方程可以迭代成功,我们还需要确定一些初始条件

dp[-1][k][0] = 0
# 因为 i 是从 0 开始的,所以 i = -1 意味着还没有开始,这时候的利润当然是 0 。
dp[-1][k][1] = -infinity
# 还没开始的时候,是不可能持有股票的,用负无穷表示这种不可能。
dp[i][0][0] = 0
# 因为 k 是从 1 开始的,所以 k = 0 意味着根本不允许交易,这时候利润当然是 0 。
dp[i][0][1] = -infinity
# 不允许交易的情况下,是不可能持有股票的,用负无穷表示这种不可能。

将上述结论汇总如下:

#初始条件:
dp[-1][k][0] = dp[n][0][0] = 0
dp[-1][k][1] = dp[n][0][1] = -infinity

#状态转移方程:
dp[n][k][0] = max(dp[n-1][k][0], dp[n-1][k][1] + prices[n])
dp[n][k][1] = max(dp[n-1][k][1], dp[n-1][k-1][0] - prices[n])

这样我们就可以针对买卖股票的问题一一作答

121. 买卖股票的最佳时机

def maxProfit(prices):
    #采用股票买卖的标准模板计算
    #
    import numpy as np
    n = len(prices)
    #因为只能进行一次买卖,所以不需要考虑k的情况
    dp_0,dp_1 = [0]*(n+1),[0]*(n+1)
    # 显然一开始没有持有股票的利润为0,而一开始持有股票是不可能的情况
    dp_0[-1] = 0
    dp_1[-1] = np.float('-inf')
    for i in range(n):
        dp_0[i] = max(dp_0[i-1],dp_1[i-1] + prices[i])
        dp_1[i] = max(dp_1[i-1],-prices[i])
    return dp_0[n-1]

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

相比于第一次只能完成1次交易而言,这一次可以完成多次交易

def maxProfit(prices):
    # 运用模板进行计算,常规参数
    import numpy as np
    n = len(prices)
    dp_0 = [0]*(n+1)
    dp_1 = [0]*(n+1)
    dp_0[-1] = 0
    dp_1[-1] = np.float('-inf')
    #这里是针对不同问题需要调整的地方
    for i in range(n):
        temp = dp_0[i-1]
        dp_0[i] = max(dp_0[i-1],dp_1[i-1]+prices[i])
        dp_1[i] = max(dp_1[i-1],temp-prices[i])
    return dp_0[n-1]

下面两道题是在以上基础上进行了一个变换

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

def maxProfit(prices):
    if prices is None or prices is []:return 0
    #采用股票买卖的标准模板计算
    import numpy as np
    n = len(prices)
    dp_0,dp_1 = [0]*(n+2),[0]*(n+2)
    dp_0[-1] = 0
    dp_1[-1] = np.float('-inf')
    dp_0[-2] = 0
    #逻辑修改的地方
    for i in range(n):
        dp_0[i] = max(dp_0[i-1],dp_1[i-1] + prices[i])
        dp_1[i] = max(dp_1[i-1],dp_0[i-2] - prices[i])
    return dp_0[n-1]

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

def maxProfit(prices, fee):
    #常规的计算模板,参数设定
    import numpy as np
    n = len(prices)
    dp_0,dp_1 = [0]*(n+1),[0]*(n+1)
    dp_0[-1] = 0
    dp_1[-1] = np.float('-inf')
    #这里要依据题设进行修改
    for i in range(n):
        dp_0[i] = max(dp_0[i-1],dp_1[i-1]+prices[i])
        dp_1[i] = max(dp_1[i-1],dp_0[i-1] - prices[i] - fee)
    return dp_0[n-1]

以下两道题考虑了交易次数的变化,属于困难题

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

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

def maxProfit(k, prices):
    #采用股票买卖的标准模板计算
    import numpy as np
    n = len(prices)
    deal = [0]*k
    dp_0,dp_1 = [deal]*(n+1),[deal]*(n+1)
    for i in range(n):
        for j in range(1,k+1):
            dp_0[-1][j] = 0
            dp_1[-1][j] = -prices[i]
            dp_0[i][j] = max(dp_0[i-1][j],dp_1[i-1][j] + prices[i])
            dp_1[i][j] = max(dp_1[i-1][j],dp_0[i-1][j-1]-prices[i])
    return dp_0[n-1][k]

 

你可能感兴趣的:(leetcode)