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

leetcode

 

解题思路

本题要求计算最多完成​​两次交易​​的最大股票利润,核心在于动态规划的状态设计。需要维护四个状态变量,分别表示:

  1. ​​第一次买入后​​的最大利润

  2. ​​第一次卖出后​​的最大利润

  3. ​​第二次买入后​​的最大利润

  4. ​​第二次卖出后​​的最大利润

通过遍历价格数组,每日更新这四个状态,最终返回第二次卖出后的利润值(即最大利润)。

 


关键步骤

  1. ​​状态初始化​​:

    • buy1 = -prices[0]:第一天买入股票,利润为负的股价

    • sell1 = 0:第一天无法卖出,利润为0

    • buy2 = -prices[0]:假设第一天完成第一次交易后再次买入

    • sell2 = 0:第一天无法完成第二次卖出

  2. ​​遍历更新状态​​(从第2天开始):

    • ​​更新第一次买入​​:buy1 = max(保持前一天状态, 今日买入:-prices[i])

    • ​​更新第一次卖出​​:sell1 = max(保持前一天状态, 今日卖出:buy1 + prices[i])

    • ​​更新第二次买入​​:buy2 = max(保持前一天状态, 今日买入:sell1 - prices[i])(用第一次卖出利润抵消成本)

    • ​​更新第二次卖出​​:sell2 = max(保持前一天状态, 今日卖出:buy2 + prices[i])

  3. ​​终止条件​​:遍历完成后返回 sell2(包含0/1/2次交易的最大值)。


代码实现

func maxProfit(prices []int) int {
    if len(prices) < 2 {
        return 0
    }
    // 初始化四个状态
    buy1 := -prices[0]
    sell1 := 0
    buy2 := -prices[0]
    sell2 := 0

    // 从第二天开始遍历
    for i := 1; i < len(prices); i++ {
        // 更新第一次交易状态
        buy1 = max(buy1, -prices[i])       // 买入或不操作
        sell1 = max(sell1, buy1+prices[i]) // 卖出或不操作

        // 更新第二次交易状态
        buy2 = max(buy2, sell1-prices[i])  // 用第一次利润买入
        sell2 = max(sell2, buy2+prices[i]) // 第二次卖出
    }

    return sell2
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}

代码解析:

  • ​​初始化​​:处理边界情况(数组长度≤1),并设置初始状态。

  • ​​状态更新​​:

    • ​​第一次买入​​:比较“保持之前买入状态”与“今日买入”的成本,取最小值(负值最大)。

    • ​​第一次卖出​​:比较“保持之前卖出状态”与“今日卖出”的利润(买入成本+当前价格)。

    • ​​第二次买入​​:用第一次卖出的利润抵消当前股价成本。

    • ​​第二次卖出​​:第二次买入成本加上当前价格。

  • ​​返回值​​:sell2天然包含0~2次交易的最大值(例如全跌时返回0)。


示例测试

func main() {
    // 示例1:输出6(交易:[4-6天], [7-8天])
    prices1 := []int{3, 3, 5, 0, 0, 3, 1, 4}
    fmt.Println(maxProfit(prices1))

    // 示例2:输出4(交易:[1-5天])
    prices2 := []int{1, 2, 3, 4, 5}
    fmt.Println(maxProfit(prices2))

    // 示例3:输出0(无交易)
    prices3 := []int{7, 6, 4, 3, 1}
    fmt.Println(maxProfit(prices3))

    // 示例4:输出0(单元素数组)
    prices4 := []int{1}
    fmt.Println(maxProfit(prices4))
}

复杂度分析

​​维度​​

​​结果​​

​​说明​​

​​时间复杂度​​

O(n)

遍历数组一次,n为数组长度

​​空间复杂度​​

O(1)

仅使用4个常量存储状态变量


关键点总结

  1. ​​状态设计​​:

    • 四个状态变量覆盖两次交易的完整生命周期(买入→卖出→再买入→再卖出)。

    • 状态转移依赖​​前一日状态​​与​​当日操作​​的组合。

  2. ​​初始化逻辑​​:

    • buy2初始化为 -prices[0]是关键,表示“第一天完成第一次交易后立即买入第二次”。 

  3. ​​贪心与动态规划的融合​​:

    • 每次更新状态时,都选择​​局部最优解​​(如买入成本最低、卖出利润最高),最终得到全局最优。

  4. ​​边界处理​​:

    • 数组长度≤1时直接返回0。

    • 全下跌行情时,sell2能正确返回0(通过 max函数保证不出现负利润)。

  5. ​​与单次交易的差异​​:

    • 单次交易只需维护 buy和 sell,而两次交易需扩展为四个状态,且第二次买入依赖第一次卖出的利润。

posted @ 2025-07-26 18:01  云隙之间  阅读(10)  评论(0)    收藏  举报