Hard草稿★★★★O(n) 時間 · O(1) 空間
ArrayDynamic Programming
Patterns🔲 網格・雙序列 DP
尚未複習過

解法已隱藏 — 先讀題目敘述、自己想想看,再點上方按鈕揭曉。

123Best Time to Buy and Sell Stock III2-D DPHard2-D DP

給定每日股價 prices最多完成兩筆交易(買賣各算一次,且必須先賣再買,不能同時持有多股),求最大利潤。

Example:

Input: prices = [3,3,5,0,0,3,1,4] Output: 6(第 4 天買 0、第 6 天賣 3,賺 3;第 7 天買 1、第 8 天賣 4,賺 3)

Input: prices = [1,2,3,4,5] Output: 4(一筆交易買 1 賣 5;第二筆用不上)

Intuition

TIP

核心思路:用四個狀態變數依序遞推——第一次買、第一次賣、第二次買、第二次賣,每天更新到最佳。

Approaches

1. 2D DP (transactions × holding) — O(n·k) / O(n·k)
  • Idea: dp[i][j][持股] 表示前 i 天、用了 j 次交易、是否持股的最大利潤(k = 2)
  • Time: O(n·k) - k = 2
  • Space: O(n·k)
class Solution {
    fun maxProfit(prices: IntArray): Int {
        val n = prices.size
        if (n == 0) return 0
        val k = 2
        // hold[j] / cash[j]:用了 j 次交易、持股 / 不持股的最大利潤
        val hold = IntArray(k + 1) { Int.MIN_VALUE }
        val cash = IntArray(k + 1)
        for (p in prices) {
            for (j in 1..k) {
                hold[j] = maxOf(hold[j], cash[j - 1] - p)   // 第 j 次買
                cash[j] = maxOf(cash[j], hold[j] + p)       // 第 j 次賣
            }
        }
        return cash[k]
    }
}
⭐ 2. Four Rolling State Variables — O(n) / O(1)
  • Idea: k = 2 時直接展開成四個變數,省去陣列
  • Time: O(n) - 掃描一次
  • Space: O(1)
class Solution {
    fun maxProfit(prices: IntArray): Int {
        var buy1 = Int.MIN_VALUE; var sell1 = 0
        var buy2 = Int.MIN_VALUE; var sell2 = 0
        for (p in prices) {
            buy1 = maxOf(buy1, -p)          // 第一次買:花 p
            sell1 = maxOf(sell1, buy1 + p)  // 第一次賣
            buy2 = maxOf(buy2, sell1 - p)   // 用第一次的利潤再買
            sell2 = maxOf(sell2, buy2 + p)  // 第二次賣 → 答案
        }
        return sell2
    }
}

🔑 Takeaways

Ladders 看全部 →

📈

買賣股票

從一次交易的貪心,長成多狀態 DP。

  1. 1#121Best Time to Buy and Sell StockEasy只能買賣一次 → 記錄歷史最低價
  2. 2#122Best Time to Buy And Sell Stock IIMedium可無限次 → 貪心吃下每一段上漲
  3. 3
  4. 4#309Best Time to Buy and Sell Stock with CooldownMedium加入冷卻期 → 多一個 cooldown 狀態
  5. 5