Coin Change
Fewest coins summing to amount — bottom-up unbounded knapsack.
3 min read
dp knapsack
Problem#
Given coin denominations and an amount, return the fewest coins summing to amount, or -1 if impossible.
Examples#
coins = [1,2,5], amount = 11→3(5+5+1)coins = [2], amount = 3→-1
Constraints#
1 <= coins.length <= 12,0 <= amount <= 10^4.
Approach#
dp[a] = fewest coins for amount a. Initialize to amount + 1 (sentinel for impossible). dp[0] = 0. Transition: dp[a] = min(dp[a - c] + 1) for each coin c <= a.
Solution#
class Solution {public: int coinChange(vector<int>& coins, int amount) { vector<int> dp(amount + 1, amount + 1); dp[0] = 0; for (int a = 1; a <= amount; ++a) { for (int c : coins) { if (c <= a) dp[a] = min(dp[a], dp[a - c] + 1); } } return dp[amount] > amount ? -1 : dp[amount]; }};func coinChange(coins []int, amount int) int { dp := make([]int, amount+1) for i := range dp { dp[i] = amount + 1 } dp[0] = 0 for a := 1; a <= amount; a++ { for _, c := range coins { if c <= a && dp[a-c]+1 < dp[a] { dp[a] = dp[a-c] + 1 } } } if dp[amount] > amount { return -1 } return dp[amount]}from typing import List
class Solution: def coinChange(self, coins: List[int], amount: int) -> int: dp = [amount + 1] * (amount + 1) dp[0] = 0 for a in range(1, amount + 1): for c in coins: if c <= a and dp[a - c] + 1 < dp[a]: dp[a] = dp[a - c] + 1 return -1 if dp[amount] > amount else dp[amount]var coinChange = function(coins, amount) { const dp = new Array(amount + 1).fill(amount + 1); dp[0] = 0; for (let a = 1; a <= amount; a++) { for (const c of coins) { if (c <= a && dp[a - c] + 1 < dp[a]) { dp[a] = dp[a - c] + 1; } } } return dp[amount] > amount ? -1 : dp[amount];};class Solution { public int coinChange(int[] coins, int amount) { int[] dp = new int[amount + 1]; Arrays.fill(dp, amount + 1); dp[0] = 0; for (int a = 1; a <= amount; a++) { for (int c : coins) { if (c <= a && dp[a - c] + 1 < dp[a]) { dp[a] = dp[a - c] + 1; } } } return dp[amount] > amount ? -1 : dp[amount]; }}function coinChange(coins: number[], amount: number): number { const dp: number[] = new Array(amount + 1).fill(amount + 1); dp[0] = 0; for (let a = 1; a <= amount; a++) { for (const c of coins) { if (c <= a && dp[a - c] + 1 < dp[a]) { dp[a] = dp[a - c] + 1; } } } return dp[amount] > amount ? -1 : dp[amount];}Editorial#
Unbounded knapsack DP. Iterating amounts outer / coins inner allows each coin to be used unlimited times naturally. The amount + 1 sentinel makes “still infeasible after the loop” a single comparison.
Complexity#
- Time: O(n * amount).
- Space: O(amount).
Concept revision#
Related#