当前位置:   article > 正文

【leetcode刷题】121. 买卖股票的最佳时机(5题汇总)(python3)_现假设给定一个数组 nums,它的第i个元素 nums[i] 表示一份给定股票第 i 天的价格

现假设给定一个数组 nums,它的第i个元素 nums[i] 表示一份给定股票第 i 天的价格

121. 买卖股票的最佳时机(简单)

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。

注意你不能在买入股票前卖出股票。

  1. class Solution:
  2. def maxProfit(self, prices: List[int]) -> int:
  3. # # 1、暴力法,两次遍历:求得所有的收益值取最大值(over time)
  4. # max_p = 0
  5. # for i in range(len(prices)):
  6. # for j in range(i,len(prices)):
  7. # tmp = prices[j]-prices[i]
  8. # max_p = max(tmp, max_p)
  9. # return max_p
  10. # # 2、暴力法优化:一次遍历,每个元素后面的最大值(8272ms)
  11. # max_p = 0
  12. # for i in range(len(prices)-1):
  13. # tmp = max(prices[i+1:])
  14. # max_p = max(tmp-prices[i], max_p)
  15. # return max_p
  16. # 3、动态规划(44ms)
  17. # 最后的元素0表示没有持有,1表示持有;最后一天是没有持有状态
  18. # 初始值没有持有收益为0,持有收益为负无穷表示不可能
  19. dp_i_0, dp_i_1 = 0, float('-inf')
  20. # 遍历每一天的情况:没有持有、持有两种可能的最大收益
  21. for i in range(len(prices)):
  22. # 当天没有表示前一天没有,或者当天卖出(当天利润为price[i]);
  23. # 当天持有表示前一天就有,或者当天买入(当天利润为-price[i])
  24. dp_i_0=max(dp_i_0, dp_i_1+prices[i])
  25. dp_i_1=max(dp_i_1, -prices[i])
  26. return dp_i_0

针对上题方法3,同方法(3D动态规划)类推以下问题。

(1)理解动态规划方法:

dp[i][k][0 or 1]
0 <= i <= n-1, 1 <= k <= K
n 为天数,大 K 为最多交易数
此问题共 n × K × 2 种状态,全部穷举就能搞定。

for 0 <= i < n:
    for 1 <= k <= K:
        for s in {0, 1}:
            dp[i][k][s] = max(buy, sell, rest)

(2)状态转移方程

dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
              max(   选择 rest  ,           选择 sell      )

解释:今天我没有持有股票,有两种可能:
要么是我昨天就没有持有,然后今天选择 rest,所以我今天还是没有持有;
要么是我昨天持有股票,但是今天我 sell 了,所以我今天没有持有股票了。

dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
              max(   选择 rest  ,           选择 buy         )

解释:今天我持有着股票,有两种可能:
要么我昨天就持有着股票,然后今天选择 rest,所以我今天还持有着股票;
要么我昨天本没有持有,但今天我选择 buy,所以今天我就持有股票了。

(3)basecase

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
解释:不允许交易的情况下,是不可能持有股票的,用负无穷表示这种不可能。

(4)状态转移方程总结:

base case:
dp[-1][k][0] = dp[i][0][0] = 0
dp[-1][k][1] = dp[i][0][1] = -infinity

状态转移方程:
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])

第1题是k=1

122. 买卖股票的最佳时机 II(简单)k=float("inf")

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

  1. class Solution:
  2. def maxProfit(self, prices: List[int]) -> int:
  3. dp_i_0, dp_i_1 = 0, float("-inf")
  4. for i in range(len(prices)):
  5. tmp = dp_i_0
  6. dp_i_0 = max(dp_i_0, dp_i_1+prices[i])
  7. dp_i_1 = max(dp_i_1,tmp-prices[i])
  8. return dp_i_0

309. 最佳买卖股票时机含冷冻期(中等)k=float("-inf")+cooldown

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

  1. class Solution:
  2. def maxProfit(self, prices: List[int]) -> int:
  3. dp_i_0, dp_i_1 = 0, float("-inf")
  4. dp_i_pre2_0 = 0 # 冷却1天,当天的持有状态,可能为两天前的未持有状态到当天售出
  5. for i in range(len(prices)):
  6. tmp = dp_i_0 # 第i-1天的未持有状态
  7. dp_i_0 = max(dp_i_0, dp_i_1+prices[i]) # 第i天的未持有状态
  8. dp_i_1 = max(dp_i_1,dp_i_pre2_0-prices[i]) # 第i天的持有状态
  9. dp_i_pre2_0 = tmp # 将第i-1天的未持有状态赋值给第i-2天,作为(i+1)-2天的未持有状态
  10. return dp_i_0

714. 买卖股票的最佳时机含手续费(中等)k=float("inf") with fee

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每次交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

  1. class Solution:
  2. def maxProfit(self, prices: List[int], fee: int) -> int:
  3. dp_i_0, dp_i_1 = 0, float("-inf")
  4. for i in range(len(prices)):
  5. tmp = dp_i_0
  6. dp_i_0 = max(dp_i_0, dp_i_1+prices[i]-fee)
  7. dp_i_1 = max(dp_i_1, tmp-prices[i])
  8. return dp_i_0

123. 买卖股票的最佳时机 III(困难)k=2

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

  1. class Solution:
  2. def maxProfit(self, prices: List[int]) -> int:
  3. dp_i_1_0, dp_i_1_1 = 0, float("-inf")
  4. dp_i_2_0, dp_i_2_1 = 0, float("-inf")
  5. for i in range(len(prices)):
  6. dp_i_2_0 = max(dp_i_2_0, dp_i_2_1 + prices[i])
  7. # 可能是前一天没有持有,今日买入,今日的交易次数为k,则前一天的交易次数为k-1
  8. # 统一买入时计入次数,也可卖出时计入次数
  9. dp_i_2_1 = max(dp_i_2_1, dp_i_1_0 - prices[i])
  10. dp_i_1_0 = max(dp_i_1_0, dp_i_1_1 + prices[i])
  11. dp_i_1_1 = max(dp_i_1_1, dp_i_0_0 - prices[i]) # 此处dp_i_0_0=0,可以不写或循环前定义初始值
  12. return dp_i_2_0

大牛原文参考链接:参考链接

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/429478
推荐阅读
相关标签
  

闽ICP备14008679号