Medium草稿★★★★★O(n) 時間 · O(1) 空間
ArrayGreedyDynamic Programming
Patterns🪙 貪心
尚未複習過

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

122Best Time to Buy And Sell Stock IIArrays & HashingMediumArrays & Hashing

給定每日股票價格陣列 prices,可以多次買賣(但同一時間只能持有一股),求最大利潤。

Example:

Input: prices = [7,1,5,3,6,4] Output: 7(第 2 天買、第 3 天賣 +4,第 4 天買、第 5 天賣 +3)

Intuition

TIP

核心思路:貪心——只要明天比今天貴,今天就買明天就賣。所有上漲段的利潤加起來就是最大利潤。

Approaches

1. DP (state machine) — O(n) / O(1)
  • Idea: 定義兩個狀態——持有股票 hold 和不持有 cash,每天更新
  • Time: O(n) - 遍歷一次
  • Space: O(1) - 只用兩個變數
class Solution {
    fun maxProfit(prices: IntArray): Int {
        var cash = 0        // 不持有股票的最大利潤
        var hold = -prices[0] // 持有股票的最大利潤
        for (i in 1 until prices.size) {
            cash = maxOf(cash, hold + prices[i])
            hold = maxOf(hold, cash - prices[i])
        }
        return cash
    }
}
⭐ 2. Greedy (sum positive diffs) — O(n) / O(1)
  • Idea: 遍歷價格,只要今天比昨天高,就把差值加入利潤
  • Time: O(n) - 一次遍歷
  • Space: O(1) - 只用一個累加器
class Solution {
    fun maxProfit(prices: IntArray): Int {
        var profit = 0
        for (i in 1 until prices.size) {
            if (prices[i] > prices[i - 1]) {
                profit += prices[i] - prices[i - 1]
            }
        }
        return profit
    }
}
Note: Peak-Valley

找到每一個谷底買入、峰頂賣出,概念上更接近「實際交易」。

class Solution {
    fun maxProfit(prices: IntArray): Int {
        var i = 0
        var profit = 0
        while (i < prices.size - 1) {
            // 找谷底
            while (i < prices.size - 1 && prices[i] >= prices[i + 1]) i++
            val valley = prices[i]
            // 找峰頂
            while (i < prices.size - 1 && prices[i] <= prices[i + 1]) i++
            profit += prices[i] - valley
        }
        return profit
    }
}

🔑 Takeaways

Ladders 看全部 →

📈

買賣股票

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

  1. 1#121Best Time to Buy and Sell StockEasy只能買賣一次 → 記錄歷史最低價
  2. 2
  3. 3#123Best Time to Buy and Sell Stock IIIHard最多兩次 → 引入交易次數狀態 DP
  4. 4#309Best Time to Buy and Sell Stock with CooldownMedium加入冷卻期 → 多一個 cooldown 狀態
  5. 5