代码随想录算法训练营Day35 | Leetcode121. 买卖股票的最佳机遇、122.买卖 ...

打印 上一主题 下一主题

主题 1943|帖子 1943|积分 5829

代码随想录算法训练营Day35 | Leetcode121.买卖股票的最佳机遇、122.买卖股票的最佳机遇II、123.买卖股票的最佳机遇III

一、买卖股票的最佳机遇

   相干题目:Leetcode121
文档讲解:Leetcode121
视频讲解:Leetcode121
  1. Leetcode121. 买卖股票的最佳机遇

   给定一个数组 prices ,它的第 i 个元素 prices 表现一支给定股票第 i 天的代价。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。计划一个算法来盘算你所能获取的最大利润。返回你可以从这笔生意业务中获取的最大利润。假如你不能获取任何利润,返回 0 。
提示:
  

  • 1 <= prices.length <= 105
  • 0 <= prices <= 104
  

  • 思绪:

    • 贪婪:由于股票就买卖一次,那么贪婪的想法很自然就是取最左最小值,取最右最大值,那么得到的差值就是最大利润。
    • 动规五部曲

      • 确定 dp 数组以及下标的寄义:dp[0] 表现第 i 天持有股票所得最多现金 ,一开始现金是 0,那么参加第 i 天买入股票现金就是 -prices。dp[1] 表现第 i 天不持有股票所得最多现金。
      • 确定递推公式

        • 假如第 i 天持有股票即 dp[0],可以由两个状态推出来:

          • 第 i-1 天就持有股票,那么保持现状,所得现金就是昨天持有股票的所得现金,即:dp[i - 1][0]。
          • 第 i 天买入股票,所得现金就是买入本日的股票后所得现金即:-prices

        则 dp[0] 应该选所得现金最大的,所以 dp[0] = max(dp[i - 1][0], -prices)
              

        • 假如第 i 天不持有股票即 dp[1], 也可以由两个状态推出来:

          • 第 i-1 天就不持有股票,那么保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]。
          • 第 i 天卖出股票,所得现金就是按照本日股票代价卖出后所得现金即:prices + dp[i - 1][0]。

        则 dp[1] 应该选所得现金最大的,所以 dp[1] = max(dp[i - 1][1], prices + dp[i - 1][0])

      • dp 数组怎样初始化:由递推公式可以看出其基础都是要从 dp[0][0] 和 dp[0][1] 推导出来,那么 dp[0][0] 表现第 0 天持有股票,此时的持有股票就一定是买入股票了,由于不可能有前一天推出来,所以 dp[0][0] -= prices[0];dp[0][1]表现第 0 天不持有股票,不持有股票那么现金就是 0,所以 dp[0][1] = 0。
      • 确定遍历次序:从递推公式可以看出 dp 都是由 dp[i - 1] 推导出来的,那么一定是从前向后遍历。
      • 举例推导 dp 数组:以输入 [7,1,5,3,6,4] 为例,dp 数组状态如下:



  • 贪婪
  1. class Solution:
  2.     def maxProfit(self, prices: List[int]) -> int:
  3.         low = float("inf")
  4.         result = 0
  5.         for i in range(len(prices)):
  6.             low = min(low, prices[i]) #取最左最小价格
  7.             result = max(result, prices[i] - low) #直接取最大区间利润
  8.         return result
复制代码


  • 动态规划
  1. ###动态规划:版本一
  2. class Solution:
  3.     def maxProfit(self, prices: List[int]) -> int:
  4.         length = len(prices)
  5.         if length == 0:
  6.             return 0
  7.         dp = [[0] * 2 for _ in range(length)]
  8.         dp[0][0] = -prices[0]
  9.         dp[0][1] = 0
  10.         for i in range(1, length):
  11.             dp[i][0] = max(dp[i-1][0], -prices[i])
  12.             dp[i][1] = max(dp[i-1][1], prices[i] + dp[i-1][0])
  13.         return dp[-1][1]
  14.         
  15. ###动态规划:版本二
  16. class Solution:
  17.     def maxProfit(self, prices: List[int]) -> int:
  18.         length = len(prices)
  19.         dp = [[0] * 2 for _ in range(2)] #注意这里只开辟了一个2 * 2大小的二维数组
  20.         dp[0][0] = -prices[0]
  21.         dp[0][1] = 0
  22.         for i in range(1, length):
  23.             dp[i % 2][0] = max(dp[(i-1) % 2][0], -prices[i])
  24.             dp[i % 2][1] = max(dp[(i-1) % 2][1], prices[i] + dp[(i-1) % 2][0])
  25.         return dp[(length-1) % 2][1]
  26.         
  27. ###动态规划:版本三
  28. class Solution:
  29.     def maxProfit(self, prices: List[int]) -> int:
  30.         length = len(prices)
  31.         dp0, dp1 = -prices[0], 0 #注意这里只维护两个常量,因为dp0的更新不受dp1的影响
  32.         for i in range(1, length):
  33.             dp1 = max(dp1, dp0 + prices[i])
  34.             dp0 = max(dp0, -prices[i])
  35.         return dp1
复制代码
二、买卖股票的最佳机遇II

   相干题目:Leetcode122
文档讲解:Leetcode122
视频讲解:Leetcode122
  1. Leetcode122.买卖股票的最佳机遇II

   给你一个整数数组 prices ,其中 prices 表现某支股票第 i 天的代价。
在每一天,你可以决定是否购买和/或出售股票。你在任何时间 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
提示:
  

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices <= 104
  

  • 思绪:

    • 本题和 Leetcode121. 买卖股票的最佳机遇 的唯一区别是本题股票可以买卖多次了,在动规五部曲中,区别主要是体如今递推公式上。
    • 递推公式

      • 假如第 i 天持有股票即 dp[0], 那么可以由两个状态推出来:

        • 第 i-1 天就持有股票,那么就保持现状,所得现金就是昨天持有股票的所得现金 即:dp[i - 1][0]。
        • 第 i 天买入股票,所得现金就是昨天不持有股票的所得现金减去本日的股票代价 即:dp[i - 1][1] - prices( Leetcode121. 买卖股票的最佳机遇 中为 -prices)。

      • 假如第 i 天不持有股票即 dp[1], 依然可以由两个状态推出来:

        • 第 i-1 天就不持有股票,那么就保持现状,所得现金就是昨天不持有股票的所得现金 即:dp[i - 1][1]。
        • 第 i 天卖出股票,所得现金就是按照本日股票代价卖出后所得现金即:prices + dp[i - 1][0]。



  • 动态规划
  1. ###版本一
  2. class Solution:
  3.     def maxProfit(self, prices: List[int]) -> int:
  4.         length = len(prices)
  5.         dp = [[0] * 2 for _ in range(length)]
  6.         dp[0][0] = -prices[0]
  7.         dp[0][1] = 0
  8.         for i in range(1, length):
  9.             dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]) #注意这里是和121. 买卖股票的最佳时机唯一不同的地方
  10.             dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i])
  11.         return dp[-1][1]
  12.         
  13. ###版本二:
  14. class Solution:
  15.     def maxProfit(self, prices: List[int]) -> int:
  16.         length = len(prices)
  17.         dp = [[0] * 2 for _ in range(2)] #注意这里只开辟了一个2 * 2大小的二维数组
  18.         dp[0][0] = -prices[0]
  19.         dp[0][1] = 0
  20.         for i in range(1, length):
  21.             dp[i % 2][0] = max(dp[(i-1) % 2][0], dp[(i-1) % 2][1] - prices[i])
  22.             dp[i % 2][1] = max(dp[(i-1) % 2][1], dp[(i-1) % 2][0] + prices[i])
  23.         return dp[(length-1) % 2][1]
复制代码
三、买卖股票的最佳机遇III

   相干题目:Leetcode123
文档讲解:Leetcode123
视频讲解:Leetcode123
  1. Leetcode123.买卖股票的最佳机遇III

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

  • 1 <= prices.length <= 105
  • 0 <= prices <= 105
  

  • 思绪:

    • 动规五部曲

      • 确定 dp 数组以及下标的寄义:一天一共有五个状态:

        • 没有利用 (实在我们也可以不设置这个状态)
        • 第一次持有股票
        • 第一次不持有股票
        • 第二次持有股票
        • 第二次不持有股票

      dp[j] 中 i 表现第 i 天,j 为 [0 - 4] 分别表现五个状态,dp[j] 表现第 i 天状态 j 所剩最大现金。(注意:dp[1] 表现的是第 i 天买入股票的状态,并不是说一定要第 i 天买入股票,有可能第 i-1 天 就买入了)
           

      • 确定递推公式

        • 达到 dp[1] 状态,有两种详细利用:

          • 利用一:第 i 天买入股票了,那么 dp[1] = dp[i-1][0] - prices
          • 利用二:第 i 天没有利用,而是沿用前一天买入的状态,即:dp[1] = dp[i - 1][1];

        那么 dp[1] 一定是选最大的,所以 dp[1] = max(dp[i-1][0] - prices, dp[i - 1][1])。
              

        • 同理达到 dp[2] 状态也有两种利用:

          • 利用一:第 i 天卖出股票了,那么 dp[2] = dp[i - 1][1] + prices
          • 利用二:第 i 天没有利用,沿用前一天卖出股票的状态,即:dp[2] = dp[i - 1][2];

        所以 dp[2] = max(dp[i - 1][1] + prices, dp[i - 1][2])。同理可推出剩下状态部分:
              

        • dp[3] = max(dp[i - 1][3], dp[i - 1][2] - prices);
        • dp[4] = max(dp[i - 1][4], dp[i - 1][3] + prices)。

      • dp 数组怎样初始化

        • 第 0 天没有利用就是 0,即:dp[0][0] = 0;
        • 第 0 天做第一次买入的利用,dp[0][1] = -prices[0];
        • 第 0 天做第一次卖出相称于当天买入,当天卖出,所以 dp[0][2] = 0;
        • 第 0 天第二次买入相称于第 0 天第一次买入后第一次卖出了,然后再买入一次(第二次买入),那么如今手头上没有现金,只要买入,现金就做相应的淘汰。所以初始化为:dp[0][3] = -prices[0];
        • 同理第 0 天第二次卖出初始化 dp[0][4] = 0。

      • 确定遍历次序:从递归公式可以看出一定是从前向后遍历,由于 dp 依赖 dp[i - 1] 的数值。
      • 举例推导 dp 数组:以输入 [1,2,3,4,5] 为例,dp 数组为:



  • 动态规划
  1. ###版本一:
  2. class Solution:
  3.     def maxProfit(self, prices: List[int]) -> int:
  4.         if len(prices) == 0:
  5.             return 0
  6.         dp = [[0] * 5 for _ in range(len(prices))]
  7.         dp[0][1] = -prices[0]
  8.         dp[0][3] = -prices[0]
  9.         for i in range(1, len(prices)):
  10.             dp[i][0] = dp[i-1][0]
  11.             dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
  12.             dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
  13.             dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])
  14.             dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])
  15.         return dp[-1][4]
  16. ###版本二:
  17. class Solution:
  18.     def maxProfit(self, prices: List[int]) -> int:
  19.         if len(prices) == 0:
  20.             return 0
  21.         dp = [0] * 5
  22.         dp[1] = -prices[0]
  23.         dp[3] = -prices[0]
  24.         for i in range(1, len(prices)):
  25.             dp[1] = max(dp[1], dp[0] - prices[i])
  26.             dp[2] = max(dp[2], dp[1] + prices[i])
  27.             dp[3] = max(dp[3], dp[2] - prices[i])
  28.             dp[4] = max(dp[4], dp[3] + prices[i])
  29.         return dp[4]
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

西河刘卡车医

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表