自学内容网 自学内容网

【LeetCode】动态规划—123. 买卖股票的最佳时机 III(附完整Python/C++代码)

题目描述

在这里插入图片描述

前言

买卖股票的最佳时机 III 是一个动态规划问题的经典变种。给定一个数组 prices,其中 prices[i] 代表第 i 天的股票价格。你最多可以进行 两次交易(一次交易包含一次买入和一次卖出),目标是通过这两次交易获得最大的利润。该问题的难点在于如何合理规划买卖时机,以获取最大收益。


基本思路

1. 问题定义

给定一个数组 prices,其中 prices[i] 表示股票第 i 天的价格。你最多可以进行两次交易,求这两次交易所能获取的最大利润。注意:两次交易不能交叉进行(必须卖掉一次股票才能再次买入)。

2. 理解问题和递推关系

为了解决该问题,我们可以将其拆解为两个阶段:

  1. 第一次交易:在某天买入并在稍后的一天卖出,获取第一次交易的最大利润。
  2. 第二次交易:在某天(第一次交易之后)再次买入股票并卖出,获取第二次交易的最大利润。

状态定义:

我们可以定义 4 个状态:

  1. first_buy[i]:表示在第 i 天结束时,我们第一次买入股票时的最大收益。
  2. first_sell[i]:表示在第 i 天结束时,我们第一次卖出股票时的最大收益。
  3. second_buy[i]:表示在第 i 天结束时,我们第二次买入股票时的最大收益。
  4. second_sell[i]:表示在第 i 天结束时,我们第二次卖出股票时的最大收益。

状态转移公式:

  1. 第一次买入的状态转移
    f i r s t _ b u y [ i ] = max ⁡ ( f i r s t _ b u y [ i − 1 ] , − p r i c e s [ i ] ) first\_buy[i] = \max(first\_buy[i-1], -prices[i]) first_buy[i]=max(first_buy[i1],prices[i])

    • 要么我们保持之前的状态不变,继续持有第一次买入的股票;
    • 要么在第 i 天以当前价格 prices[i] 买入股票。
  2. 第一次卖出的状态转移
    f i r s t _ s e l l [ i ] = max ⁡ ( f i r s t _ s e l l [ i − 1 ] , f i r s t _ b u y [ i − 1 ] + p r i c e s [ i ] ) first\_sell[i] = \max(first\_sell[i-1], first\_buy[i-1] + prices[i]) first_sell[i]=max(first_sell[i1],first_buy[i1]+prices[i])

    • 要么我们保持之前的状态不变,继续持有卖出后的最大利润;
    • 要么在第 i 天卖出股票,利润为 first_buy[i-1] + prices[i]
  3. 第二次买入的状态转移
    s e c o n d _ b u y [ i ] = max ⁡ ( s e c o n d _ b u y [ i − 1 ] , f i r s t _ s e l l [ i − 1 ] − p r i c e s [ i ] ) second\_buy[i] = \max(second\_buy[i-1], first\_sell[i-1] - prices[i]) second_buy[i]=max(second_buy[i1],first_sell[i1]prices[i])

    • 要么我们保持之前的状态不变,继续持有第二次买入的股票;
    • 要么在第 i 天买入股票,利润为 first_sell[i-1] - prices[i]
  4. 第二次卖出的状态转移
    s e c o n d _ s e l l [ i ] = max ⁡ ( s e c o n d _ s e l l [ i − 1 ] , s e c o n d _ b u y [ i − 1 ] + p r i c e s [ i ] ) second\_sell[i] = \max(second\_sell[i-1], second\_buy[i-1] + prices[i]) second_sell[i]=max(second_sell[i1],second_buy[i1]+prices[i])

    • 要么我们保持之前的状态不变,继续持有第二次卖出的最大利润;
    • 要么在第 i 天卖出股票,利润为 second_buy[i-1] + prices[i]

初始条件:

  • first_buy[0] = -prices[0],第一次买入的初始状态。
  • first_sell[0] = 0,第一次卖出的初始状态。
  • second_buy[0] = -prices[0],第二次买入的初始状态。
  • second_sell[0] = 0,第二次卖出的初始状态。

3. 解决方法

动态规划方法

  1. 定义 4 个状态 first_buy[i]first_sell[i]second_buy[i]second_sell[i] 表示在第 i 天结束时的最大收益。
  2. 通过递推公式更新这些状态。
  3. 最终结果为 second_sell[n-1],即最多进行两次交易后在最后一天的最大利润。

伪代码:

initialize first_buy = -prices[0], first_sell = 0, second_buy = -prices[0], second_sell = 0
for i from 1 to n-1:
    first_buy = max(first_buy, -prices[i])
    first_sell = max(first_sell, first_buy + prices[i])
    second_buy = max(second_buy, first_sell - prices[i])
    second_sell = max(second_sell, second_buy + prices[i])
return second_sell

4. 进一步优化

  • 空间优化:由于每个状态只依赖于前一天的状态,我们可以将动态规划的 4 个状态用常量来代替,优化空间复杂度为 O(1)

5. 小总结

  • 问题思路:通过定义四个状态,分别对应两次买入和卖出的最大利润,使用动态规划可以有效求解。
  • 时间复杂度:该方法的时间复杂度为 O(n),空间复杂度可以优化为 O(1)

以上就是买卖股票的最佳时机 III问题的基本思路。


Python代码

class Solution:
    def maxProfit(self, prices: list[int]) -> int:
        if not prices:
            return 0

        # 初始化四个状态
        first_buy = second_buy = -prices[0]
        first_sell = second_sell = 0

        for i in range(1, len(prices)):
            # 依次更新四个状态
            first_buy = max(first_buy, -prices[i])
            first_sell = max(first_sell, first_buy + prices[i])
            second_buy = max(second_buy, first_sell - prices[i])
            second_sell = max(second_sell, second_buy + prices[i])

        # 返回最终状态的最大值
        return second_sell

Python代码解释

  1. 初始化first_buysecond_buy 初始为 -prices[0]first_sellsecond_sell 初始为 0
  2. 状态转移:通过递推公式依次更新四个状态。
  3. 返回结果:最终返回 second_sell,即最大利润。

C++代码

#include <vector>
#include <algorithm>
using namespace std;

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty()) return 0;

        // 初始化四个状态
        int first_buy = -prices[0], first_sell = 0;
        int second_buy = -prices[0], second_sell = 0;

        for (int i = 1; i < prices.size(); ++i) {
            // 依次更新四个状态
            first_buy = max(first_buy, -prices[i]);
            first_sell = max(first_sell, first_buy + prices[i]);
            second_buy = max(second_buy, first_sell - prices[i]);
            second_sell = max(second_sell, second_buy + prices[i]);
        }

        // 返回最终状态的最大值
        return second_sell;
    }
};

C++代码解释

  1. 初始化first_buysecond_buy 初始为 -prices[0]first_sellsecond_sell 初始为 0
  2. 状态转移:通过递推公式依次更新四个状态。
  3. 返回结果:最终返回 second_sell,即最大利润。

总结

  • 核心思路:通过动态规划,定义四个状态来跟踪两次买入和两次卖出的最大利润,并通过状态转移公式逐步更新,最终获取最大利润。
  • 时间复杂度:时间复杂度为 O(n),适合处理大规模数据。
  • 空间优化:由于状态之间只依赖前一天的状态,空间复杂度可以优化为 O(1),这使得算法在空间效率上达到最优。

原文地址:https://blog.csdn.net/AlbertDS/article/details/142889785

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!