Medium草稿★★★★★O(n * amount) 時間 · O(amount) 空間
Dynamic ProgrammingKnapsack
Patterns🎒 背包🔲 網格・雙序列 DP
尚未複習過

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

518Coin Change II2-D DPMedium2-D DP

給定不同面額的硬幣陣列 coins 和一個總金額 amount,回傳湊成該金額的組合數。每種硬幣可以無限次使用。若無法湊成則回傳 0。

Example:

Input: amount = 5, coins = [1,2,5] Output: 4 (5, 2+2+1, 2+1+1+1, 1+1+1+1+1)

Intuition

TIP

完全背包問題:外層遍歷硬幣、內層遍歷金額,確保計算的是「組合數」而非「排列數」。

Approaches

1. 2D DP Table — O(n * amount) / O(n * amount)
  • Idea: dp[i][j] 代表用前 i 種硬幣湊成金額 j 的組合數。對每種硬幣,要麼不用(dp[i-1][j]),要麼用一枚(dp[i][j-coin])。
  • Time: O(n * amount),n 為硬幣種類數
  • Space: O(n * amount)
class Solution {
    fun change(amount: Int, coins: IntArray): Int {
        val n = coins.size
        val dp = Array(n + 1) { IntArray(amount + 1) }
        for (i in 0..n) dp[i][0] = 1
        for (i in 1..n) {
            for (j in 0..amount) {
                dp[i][j] = dp[i - 1][j]
                if (j >= coins[i - 1]) {
                    dp[i][j] += dp[i][j - coins[i - 1]]
                }
            }
        }
        return dp[n][amount]
    }
}
⭐ 2. 1D DP (Space Optimized) — O(n * amount) / O(amount)
  • Idea: 壓縮為一維,外層遍歷硬幣,內層正向遍歷金額(因為同一種硬幣可重複使用)。
  • Time: O(n * amount)
  • Space: O(amount)
class Solution {
    fun change(amount: Int, coins: IntArray): Int {
        val dp = IntArray(amount + 1)
        dp[0] = 1
        for (coin in coins) {
            for (j in coin..amount) {
                dp[j] += dp[j - coin]
            }
        }
        return dp[amount]
    }
}

🔑 Takeaways

Ladders 看全部 →

🪙

零錢 / 計數背包

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

  1. 1#322Coin ChangeMedium湊出金額的最少硬幣數
  2. 2
  3. 3#377Combination Sum IVMedium順序不同算不同(排列,金額外層)