Medium草稿★★★★★O(amount * coins.size) 時間 · O(amount) 空間
Dynamic ProgrammingBFS
Patterns🌊 廣度優先 BFS📈 線性 DP・Kadane
尚未複習過

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

322Coin Change1-D DPMedium1-D DP

給定不同面額的硬幣陣列 coins 和一個目標金額 amount,求湊成該金額所需的最少硬幣數。如果無法湊成,回傳 -1。每種硬幣數量無限。

Example:

Input: coins = [1,2,5], amount = 11 Output: 3

Intuition

TIP

完全背包問題:對每個金額,嘗試每種硬幣,取使用最少硬幣數的方案。

Approaches

1. Top-Down Memoization — O(amount * coins.size) / O(amount)
  • Idea: 遞迴嘗試每種硬幣,記憶化避免重複計算
  • Time: O(amount * coins.size)
  • Space: O(amount)
class Solution {
    fun coinChange(coins: IntArray, amount: Int): Int {
        val memo = IntArray(amount + 1) { -2 }
        fun dp(rem: Int): Int {
            if (rem == 0) return 0
            if (rem < 0) return -1
            if (memo[rem] != -2) return memo[rem]
            var best = Int.MAX_VALUE
            for (c in coins) {
                val res = dp(rem - c)
                if (res in 0 until best) best = res + 1
            }
            memo[rem] = if (best == Int.MAX_VALUE) -1 else best
            return memo[rem]
        }
        return dp(amount)
    }
}
⭐ 2. Bottom-Up DP — O(amount * coins.size) / O(amount)
  • Idea: 從金額 1 到 amount 依序填表,每次嘗試所有硬幣面額
  • Time: O(amount * coins.size)
  • Space: O(amount)
class Solution {
    fun coinChange(coins: IntArray, amount: Int): Int {
        val dp = IntArray(amount + 1) { amount + 1 }
        dp[0] = 0
        for (i in 1..amount) {
            for (c in coins) {
                if (c <= i) {
                    dp[i] = minOf(dp[i], dp[i - c] + 1)
                }
            }
        }
        return if (dp[amount] > amount) -1 else dp[amount]
    }
}

🔑 Takeaways

Ladders 看全部 →

🪙

零錢 / 計數背包

同樣是無界背包,問法決定迴圈順序。

  1. 1
  2. 2#518Coin Change IIMedium湊法總數(組合,硬幣外層)
  3. 3#377Combination Sum IVMedium順序不同算不同(排列,金額外層)