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

力扣题目链接(opens new window)

给定一个数组,它的第 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

解题思路:

  1. 定义状态: 由于最多可以进行两笔交易,我们需要跟踪四个状态:第一次买入(first_buy)、第一次卖出(first_sell)、第二次买入(second_buy)、第二次卖出(second_sell)。

  2. 初始化状态:

    • first_buy 初始化为负无穷大,因为还没有进行任何买入操作。
    • first_sellsecond_buysecond_sell 都初始化为0,因为初始利润为0。
  3. 状态转移:

    • 对于每一天的价格,更新上述四个状态。
    • first_buy:选择之前的 first_buy 或者当天的价格(负数,因为是花费)中的较大者。
    • first_sell:选择之前的 first_sell 或者今天的价格加上 first_buy(代表卖出)中的较大者。
    • second_buy:选择之前的 second_buy 或者 first_sell 减去今天的价格中的较大者。
    • second_sell:选择之前的 second_sell 或者今天的价格加上 second_buy 中的较大者。
  4. 计算结果:

    • 遍历完所有价格后,second_sell 就是最大利润。
class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        if not prices:
            return 0

        first_buy, first_sell = -float('inf'), 0
        second_buy, second_sell = -float('inf'), 0

        for price in prices:
            first_buy = max(first_buy, -price)  # 第一次买入的最佳选择
            first_sell = max(first_sell, first_buy + price)  # 第一次卖出的最佳选择
            second_buy = max(second_buy, first_sell - price)  # 第二次买入的最佳选择
            second_sell = max(second_sell, second_buy + price)  # 第二次卖出的最佳选择

        return second_sell  # 返回最大利润

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

力扣题目链接

给定一个整数数组 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

解题思路:

  1. 状态定义: 定义 dp[i][j] 作为一个二维数组,其中 i 表示天数,j 表示交易次数(每次交易包括买和卖两个动作)。dp[i][j] 表示第 i 天完成 j 笔交易能获得的最大利润。

  2. 初始化:

    • 对于 dp[0][..](即第0天),无论交易次数如何,利润都是0,因为没有交易发生。
    • 对于 dp[..][0](即没有交易),无论天数如何,利润都是0。
  3. 状态转移:

    • 需要决定第 i 天是买入、卖出还是不操作。这可以通过比较不同选择下的利润来决定。
    • 对于买入操作,我们要找到之前某天 m,使得 dp[m][j-1] - prices[i](即第 m 天完成 j-1 笔交易后的利润减去第 i 天的股价)最大。
    • 对于卖出操作,我们要找到之前某天 m,使得 dp[m][j-1] + prices[i] 最大。
    • 对于不操作,直接保持前一天的状态,即 dp[i][j] = dp[i-1][j]
  4. 结果计算:

    • 最后 dp[n-1][k](其中 n 是天数)就是在给定的条件下可以获得的最大利润。
class Solution:
    def maxProfit(self, k: int, prices: List[int]) -> int:
        if not prices:
            return 0

        n = len(prices)
        if k >= n // 2:
            return self.maxProfitInf(prices)

        dp = [[0] * (k + 1) for _ in range(n)]
        for j in range(1, k + 1):
            max_diff = -prices[0]
            for i in range(1, n):
                dp[i][j] = max(dp[i-1][j], prices[i] + max_diff)
                max_diff = max(max_diff, dp[i-1][j-1] - prices[i])

        return dp[-1][-1]

    def maxProfitInf(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

 

 

11-11 22:29