Medium草稿★★★★★O(n) 時間 · O(1) 空間
Dynamic ProgrammingState Machine
Patterns🔲 網格・雙序列 DP
尚未複習過

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

309Best Time to Buy and Sell Stock with Cooldown2-D DPMedium2-D DP

給定股票每天的價格陣列,可以多次買賣但賣出後隔天為冷卻期(不能買入)。求最大利潤。

Example:

Input: prices = [1,2,3,0,2] Output: 3 (買 1 賣 3,冷卻,買 0 賣 2)

Intuition

TIP

用狀態機思維:每天有「持有股票」、「不持有且在冷卻」、「不持有且非冷卻」三種狀態。

Approaches

1. 2D DP Table — O(n) / O(n)
  • Idea: 用 dp[i][state] 記錄第 i 天各狀態的最大利潤,state 為 0(rest)、1(hold)、2(sold)。
  • Time: O(n)
  • Space: O(n)
class Solution {
    fun maxProfit(prices: IntArray): Int {
        val n = prices.size
        if (n <= 1) return 0
        // dp[i][0] = rest, dp[i][1] = hold, dp[i][2] = sold
        val dp = Array(n) { IntArray(3) }
        dp[0][0] = 0
        dp[0][1] = -prices[0]
        dp[0][2] = 0
        for (i in 1 until n) {
            dp[i][0] = maxOf(dp[i - 1][0], dp[i - 1][2])
            dp[i][1] = maxOf(dp[i - 1][1], dp[i - 1][0] - prices[i])
            dp[i][2] = dp[i - 1][1] + prices[i]
        }
        return maxOf(dp[n - 1][0], dp[n - 1][2])
    }
}
⭐ 2. State Machine (Space Optimized) — O(n) / O(1)
  • Idea: 三個狀態只依賴前一天的值,用三個變數即可。
  • Time: O(n)
  • Space: O(1)
class Solution {
    fun maxProfit(prices: IntArray): Int {
        if (prices.size <= 1) return 0
        var rest = 0
        var hold = -prices[0]
        var sold = 0
        for (i in 1 until prices.size) {
            val prevRest = rest
            val prevHold = hold
            val prevSold = sold
            rest = maxOf(prevRest, prevSold)
            hold = maxOf(prevHold, prevRest - prices[i])
            sold = prevHold + prices[i]
        }
        return maxOf(rest, sold)
    }
}

🔑 Takeaways

Ladders 看全部 →

📈

買賣股票

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

  1. 1#121Best Time to Buy and Sell StockEasy只能買賣一次 → 記錄歷史最低價
  2. 2#122Best Time to Buy And Sell Stock IIMedium可無限次 → 貪心吃下每一段上漲
  3. 3#123Best Time to Buy and Sell Stock IIIHard最多兩次 → 引入交易次數狀態 DP
  4. 4
  5. 5