算法打卡day43

今日任务:

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

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

3)复习day18

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

题目链接:123. 买卖股票的最佳时机 III - 力扣(LeetCode)

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

示例 1:
输入:prices = [3,3,5,0,0,3,1,4]
输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3。

示例 2:
输入:prices = [1,2,3,4,5]
输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:
输入:prices = [7,6,4,3,1]
输出:0 解释:在这个情况下, 没有交易完成, 所以最大利润为0。

示例 4:
输入:prices = [1] 输出:0

提示:
1 <= prices.length <= 10^5
0 <= prices[i] <= 10^5

文章讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划,股票至多买卖两次,怎么求? | LeetCode:123.买卖股票最佳时机III哔哩哔哩bilibili

思路:

这个问题可以通过动态规划来解决。我们可以定义四个状态变量来表示不同的情况:

  1. buy1:表示完成第一笔交易后持有股票的最大利润。
  2. sell1:表示完成第一笔交易后不持有股票的最大利润。
  3. buy2:表示完成第二笔交易后持有股票的最大利润。
  4. sell2:表示完成第二笔交易后不持有股票的最大利润。

对于每一天,我们可以有四种操作:

  1. 保持持有状态,即不卖出,这样利润不变。
  2. 卖出股票,这样我们的利润将增加当前股票的价格。
  3. 买入股票,这样我们的利润将减少当前股票的价格。

我们的目标是选择操作使得最终的利润最大化。因此,我们可以通过比较这三种操作的结果来更新状态变量 buy1sell1buy2sell2

具体步骤如下:

  1. 首先,我们初始化四个状态变量:
    • buy1 初始化为第一天的价格的相反数,因为在第一天买入股票。
    • sell1 初始化为 0,因为在第一天不持有股票。
    • buy2 初始化为第一天的价格的相反数,因为在第一天买入股票。
    • sell2 初始化为 0,因为在第一天不持有股票。
  2. 然后,我们遍历每一天的股票价格,对于每一天,我们都更新四个状态变量:
    • 对于 buy1,我们可以选择保持持有状态(即不买入),或者买入股票。我们选择较大的值更新 buy1
    • 对于 sell1,我们可以选择保持不持有状态(即不卖出),或者卖出股票。我们选择较大的值更新 sell1
    • 对于 buy2,我们可以选择保持持有状态(即不买入),或者买入股票。我们选择较大的值更新 buy2
    • 对于 sell2,我们可以选择保持不持有状态(即不卖出),或者卖出股票。我们选择较大的值更新 sell2
  3. 最终,我们返回 sell2,因为在最后一天,我们希望不持有股票以获取最大利润。

这样,我们通过动态规划来解决了问题,时间复杂度为 O(n),其中 n 是股票价格数组的长度。

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        # 如果价格数组为空,则返回0
        if not prices:
            return 0

        # 初始化第一笔交易买入和卖出的最大利润
        buy1 = -prices[0]  # 第一笔交易买入时持有股票,初始化为第一天的股票价格的相反数
        sell1 = 0  # 第一笔交易卖出后不持有股票,初始化为0

        # 初始化第二笔交易买入和卖出的最大利润
        buy2 = -prices[0]  # 第二笔交易买入时持有股票,初始化为第一天的股票价格的相反数
        sell2 = 0  # 第二笔交易卖出后不持有股票,初始化为0

        # 遍历股票价格数组
        for price in prices[1:]:
            # 更新第一笔交易买入和卖出的最大利润
            buy1 = max(buy1, -price)  # 第一笔交易买入时持有股票,取当前持有和之前持有的最大值
            sell1 = max(sell1, buy1 + price)  # 第一笔交易卖出后不持有股票,取当前不持有和之前不持有的最大值
            # 更新第二笔交易买入和卖出的最大利润
            buy2 = max(buy2, sell1 - price)  # 第二笔交易买入时持有股票,取当前持有和之前持有的最大值
            sell2 = max(sell2, buy2 + price)  # 第二笔交易卖出后不持有股票,取当前不持有和之前不持有的最大值

        return sell2  # 返回完成两笔交易后不持有股票的最大利润

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

题目链接:188. 买卖股票的最佳时机 IV - 力扣(LeetCode)

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

示例 1:
输入:k = 2, prices = [2,4,1]
输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2。

示例 2:
输入:k = 2, prices = [3,2,6,5,0,3]
输出:7 解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。

提示:
0 <= k <= 100
0 <= prices.length <= 1000
0 <= prices[i] <= 1000

文章讲解:代码随想录 (programmercarl.com)

视频讲解:动态规划来决定最佳时机,至多可以买卖K次!| LeetCode:188.买卖股票最佳时机4哔哩哔哩bilibili

思路:

  1. 首先检查输入的 prices 数组的长度是否小于2,如果是,则直接返回0,因为不可能完成交易。
  2. 接着判断如果 k 大于等于数组长度的一半,说明可以进行无限次交易(因为一次交易至少需要两天),那么可以直接使用贪心算法来解决问题,调用 maxProfitGreedy 函数即可。
  3. 如果 k 小于数组长度的一半,则进入动态规划解决问题。
  4. 动态规划的状态 dp 是一个长度为 2k+1 的数组,其中 dp[2*i+1] 表示在第 i 次交易后持有股票的最大利润,dp[2*i+2] 表示在第 i 次交易后不持有股票的最大利润。
  5. 初始化时,对于每一次交易 i,初始化 dp[2*i+1] 为第一天的股票价格的负值,表示第一天购买股票的情况。而 dp[2*i+2] 则初始化为0,表示不持有股票时的利润为0。
  6. 遍历价格数组中的每一天,对于每一次交易 i,更新 dp[2*i+1]dp[2*i+2] 的值:
    • 对于 dp[2*i+1],表示在第 i 次交易后持有股票的最大利润,更新为前一天持有股票利润 dp[2*i+1] 和当前股票价格 price 的较大值。
    • 对于 dp[2*i+2],表示在第 i 次交易后不持有股票的最大利润,更新为前一天不持有股票利润 dp[2*i+2] 和前一次持有股票利润加上当前股票价格 price 的较大值。
  7. 最后返回 dp[-1],即完成了k次交易后不持有股票的最大利润。
class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        n = len(prices)
        if n < 2:
            return 0

        # 如果k超过了天数的一半,那么相当于可以进行无限次交易,因此可以直接返回贪心解法的结果
        if k >= n // 2:
            return self.maxProfitGreedy(prices)

        # 初始化
        dp = [0]*(2*k+1)
        for i in range(k):
            dp[2*i+1]=-prices[0]


        for price in prices[1:]:
            for i in range(k):
                dp[2*i+1] = max(dp[2*i+1],dp[2*i]-price)
                dp[2*i+2] = max(dp[2*i+2],dp[2*i+1]+price)

        return dp[-1]

    def maxProfitGreedy(self, prices: List[int]) -> int:
        profit = 0
        for i in range(1, len(prices)):
            if prices[i] > prices[i - 1]:
                profit += prices[i] - prices[i - 1]
        return profit

  • 24
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值