Coin Change
Coin Change Problem
š§© Problem Statement
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1.
You may assume that you have an infinite number of each kind of coin.
š¹ Example 1:
Input:
coins = [1,2,5], amount = 11
Output:
3
Explanation: 11 = 5 + 5 + 1.
š¹ Example 2:
Input:
coins = [2], amount = 3
Output:
-1
š Approaches
1. Dynamic Programming (Unbounded Knapsack Pattern)
This is an Unbounded Knapsack problem because we can use each coin multiple times. We want to minimize the number of items (coins) to reach a specific capacity (amount).
Tabulation (Bottom-Up):
Create a 1D array dp of size amount + 1.
dp[i]represents the minimum coins needed to make amounti.- Initialization:
dp[0] = 0(0 coins needed for 0 amount).dp[i] = infinityfori > 0(initially unreachable).- Transition:
- Iterate through all amounts from
1toamount. - For each
coinincoins: - If
i - coin >= 0anddp[i - coin] != infinity: dp[i] = min(dp[i], dp[i - coin] + 1)
Finally, ifdp[amount]is still infinity, return-1.
ā³ Time & Space Complexity
- Time Complexity: $O(S \cdot N)$, where $S$ is the amount and $N$ is the number of coin denominations.
- Space Complexity: $O(S)$ for the DP array.
š Code Implementations
C++
#include <vector>
#include <algorithm>
#include <climits>
using namespace std;
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
// Initialize dp array with amount + 1 (impossible max value)
vector<int> dp(amount + 1, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int coin : coins) {
if (i - coin >= 0) {
dp[i] = min(dp[i], dp[i - coin] + 1);
}
}
}
return (dp[amount] > amount) ? -1 : dp[amount];
}
};
Python
from typing import List
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
# Initialize dp array with amount + 1
dp = [amount + 1] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
for coin in coins:
if i - coin >= 0:
dp[i] = min(dp[i], dp[i - coin] + 1)
return dp[amount] if dp[amount] <= amount else -1
Java
import java.util.Arrays;
class Solution {
public int coinChange(int[] coins, int amount) {
int max = amount + 1;
int[] dp = new int[amount + 1];
Arrays.fill(dp, max);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
for (int coin : coins) {
if (i - coin >= 0) {
dp[i] = Math.min(dp[i], dp[i - coin] + 1);
}
}
}
return (dp[amount] > amount) ? -1 : dp[amount];
}
}
š Real-World Analogy
Vending Machine Change:
The machine wants to dispense exactly $X amount of change using the fewest coins possible to keep its hopper full. It checks combinations of quarters, dimes, nickels...
šÆ Summary
ā
Unbounded Knapsack: Use items multiple times.
ā
Minimization Problem: Initialize with infinity, use min() function.
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
int coinChange(vector<int> &coins, int amount) {
// Initialize dp array with amount + 1 (impossible max value since min coin
// is 1)
vector<int> dp(amount + 1, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; ++i) {
for (int coin : coins) {
if (i - coin >= 0) {
dp[i] = min(dp[i], dp[i - coin] + 1);
}
}
}
return (dp[amount] > amount) ? -1 : dp[amount];
}
};
int main() {
Solution sol;
vector<int> coins1 = {1, 2, 5};
int amount1 = 11;
cout << "Test Case 1 (Amt 11): " << sol.coinChange(coins1, amount1)
<< endl; // Expect 3
vector<int> coins2 = {2};
int amount2 = 3;
cout << "Test Case 2 (Amt 3): " << sol.coinChange(coins2, amount2)
<< endl; // Expect -1
vector<int> coins3 = {1};
int amount3 = 0;
cout << "Test Case 3 (Amt 0): " << sol.coinChange(coins3, amount3)
<< endl; // Expect 0
return 0;
}