DP算法问题写这些题就够了 123. 买卖股票的最佳时机 III【第三题】

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

题目描述

给定一个数组,它的第 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。
  • 总利润为 3 + 3 = 6。
示例 2:

输入

prices = [1,2,3,4,5]

输出

4

解释

  • 在第 1 天买入,在第 5 天卖出,利润为 5 - 1 = 4。
示例 3:

输入

prices = [7,6,4,3,1]

输出

0

解释

  • 由于股票价格在整个时间段内不断下降,没有交易可以完成,最大利润为 0。
示例 4:

输入

prices = [1]

输出

0

解释

  • 只有一天的数据,无法进行任何交易,最大利润为 0。

解题思路

在这里插入图片描述

我们可以使用动态规划来解决这个问题,设定一个 dp 数组,记录在不同状态下的最大利润。

状态定义:

  • dp[i][1]:第 i 天时,持有股票并且完成了第一次买入。
  • dp[i][2]:第 i 天时,不持有股票并且完成了第一次卖出。
  • dp[i][3]:第 i 天时,持有股票并且完成了第二次买入。
  • dp[i][4]:第 i 天时,不持有股票并且完成了第二次卖出。

由于我们有两笔交易,所以状态总共包括 4 个阶段。每一天,我们都可以选择继续持有股票、卖出股票或者买入股票。

初始化时,将所有状态初始化为极小值(-∞),以确保从头开始时,必须通过买入才能开始盈利。

动态规划转移方程:
  • dp[i][1] = max(dp[i-1][1], -prices[i-1]):表示第一次买入股票,选择继续持有或者当天买入。
  • dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i-1]):表示第一次卖出股票,选择继续持有第一次卖出的状态,或者在第 i 天卖出。
  • dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i-1]):表示第二次买入股票,选择继续持有第二次买入的状态,或者在第 i 天买入。
  • dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i-1]):表示第二次卖出股票,选择继续持有第二次卖出的状态,或者在第 i 天卖出。

最终结果:

  • 最终答案为 max(dp[n][4], dp[n][2]),即完成最多两次交易后的最大利润,可能是仅完成第一次卖出的利润或第二次卖出的利润。

代码实现

from typing import List

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        n = len(prices)
        if n == 0:
            return 0
        
        # dp[i][1]: 持有股票并且第一次买入
        # dp[i][2]: 不持有股票并且卖出了第一次股票
        # dp[i][3]: 持有股票并且第二次买入
        # dp[i][4]: 不持有股票并且卖出了第二次股票
        dp = [[-2e9] * 5 for _ in range(n + 1)]  # 初始化为极小值
        
        for i in range(1, n + 1):
            dp[i][1] = max(dp[i-1][1], -prices[i-1])  # 第一次买入股票
            dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i-1])  # 第一次卖出股票
            dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i-1])  # 第二次买入股票
            dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i-1])  # 第二次卖出股票
        
        # 返回完成最多两次交易后的最大利润
        return max(0, dp[n][4], dp[n][2])  # 可以是第二次卖出(dp[n][4])或者仅卖出第一次股票(dp[n][2])

时间复杂度与空间复杂度

  • 时间复杂度O(n),其中 n 为价格数组的长度。我们只需要遍历一次价格数组,更新 dp 数组的值。
  • 空间复杂度O(n),我们使用了一个 n+1 长度的二维数组 dp 来记录状态。

结语

该问题通过动态规划来模拟最大利润的计算过程,考虑了两次交易的情况。通过合理的状态转换,能够高效地得出结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值