Problem: Coin Change (Minimum Coins)
You are given a list of coins with different denominations and a target amount. The goal is to determine the fewest number of coins needed to make up that amount. If it’s impossible to make up that amount, return -1
.
Dynamic Programming Approach Explanation:
This is a classic problem that can be solved using Dynamic Programming (DP). We will use a bottom-up approach where we build the solution incrementally, starting from the smallest subproblems (amount 0) and gradually increasing to the target amount.
Concept:
-
State Representation:
Letdp[i]
represent the fewest number of coins required to make amounti
. -
Initialization:
- Set
dp[0] = 0
, because zero amount requires zero coins. - For other amounts
i > 0
, initializedp[i] = infinity
(or a large value) because initially, we assume it’s impossible to form that amount.
- Set
-
State Transition:
For each coin denomination, update thedp
array. If we can make the amounti - coin
, then we can make the amounti
by adding one more coin. Therefore:dp[i]=min(dp[i],dp[i−coin]+1)dp[i] = min(dp[i], dp[i – coin] + 1)
-
Final Answer:
After processing all coins,dp[amount]
will give the minimum number of coins required for the target amount. Ifdp[amount]
is still infinity, it means the target amount cannot be formed with the given coins, and we return-1
.
Example:
Input:coins = [1, 2, 5]
, amount = 11
Step-by-step DP Table:
Amount | dp[Amount] | Explanation |
---|---|---|
0 | 0 | No coins needed for amount 0 |
1 | 1 | Use one coin of 1 |
2 | 1 | Use one coin of 2 |
3 | 2 | Use one coin of 2 + one coin of 1 |
4 | 2 | Use two coins of 2 |
5 | 1 | Use one coin of 5 |
6 | 2 | Use one coin of 5 + one coin of 1 |
7 | 2 | Use one coin of 5 + two coins of 1 |
8 | 3 | Use one coin of 5 + one coin of 2 |
9 | 3 | Use one coin of 5 + two coins of 2 |
10 | 2 | Use two coins of 5 |
11 | 3 | Use one coin of 5 + one coin of 5 + one coin of 1 |
Answer: 3
, because we need 3 coins: 5 + 5 + 1
.
C Code:
#include <stdio.h>
#include <limits.h>
int coinChange(int* coins, int coinsSize, int amount) {
int dp[amount + 1];
// Initialize the dp array with a large value
for (int i = 0; i <= amount; i++) {
dp[i] = INT_MAX;
}
dp[0] = 0; // No coins needed to make amount 0
// Bottom-up DP
for (int i = 1; i <= amount; i++) {
for (int j = 0; j < coinsSize; j++) {
if (i >= coins[j] && dp[i - coins[j]] != INT_MAX) {
dp[i] = dp[i] < dp[i - coins[j]] + 1 ? dp[i] : dp[i - coins[j]] + 1;
}
}
}
// If dp[amount] is still INT_MAX, it means we cannot form the amount
return dp[amount] == INT_MAX ? -1 : dp[amount];
}
int main() {
int coins[] = {1, 2, 5};
int coinsSize = 3;
int amount = 11;
int result = coinChange(coins, coinsSize, amount);
printf("Minimum number of coins: %dn", result);
return 0;
}
Python Code:
def coinChange(coins, amount):
# Initialize dp array with infinity, except dp[0] which is 0
dp = [float('inf')] * (amount + 1)
dp[0] = 0
# Bottom-up DP
for i in range(1, amount + 1):
for coin in coins:
if i >= coin:
dp[i] = min(dp[i], dp[i - coin] + 1)
# If dp[amount] is still infinity, return -1, otherwise return dp[amount]
return dp[amount] if dp[amount] != float('inf') else -1
# Example Usage:
coins = [1, 2, 5]
amount = 11
result = coinChange(coins, amount)
print(f"Minimum number of coins: {result}")
Explanation of Code:
-
Initialization:
- In both C and Python, the
dp
array is initialized to represent the fewest coins needed for every amount from0
toamount
. Initially, all amounts are set to a large value (INT_MAX
in C andfloat('inf')
in Python) exceptdp[0]
, which is set to 0 (because no coins are needed to make amount 0).
- In both C and Python, the
-
Filling the DP Table:
- For each amount from
1
toamount
, iterate through each coin. If we can use that coin (i.e.,i >= coin
), then update thedp[i]
value by considering using that coin: dp[i]=min(dp[i],dp[i−coin]+1)dp[i] = min(dp[i], dp[i – coin] + 1) - This ensures we get the minimum number of coins for each amount.
- For each amount from
-
Final Check:
- After filling the DP table, if
dp[amount]
is still infinity (INT_MAX
orfloat('inf')
), it means it’s not possible to make that amount with the given coins, so return-1
. Otherwise, returndp[amount]
, which is the minimum number of coins needed.
- After filling the DP table, if
Time and Space Complexity:
-
Time Complexity:
- The time complexity is O(amount * coins), where
amount
is the target amount andcoins
is the number of coin denominations. For each amount, we check every coin denomination.
- The time complexity is O(amount * coins), where
-
Space Complexity:
- The space complexity is O(amount) because we only need a
dp
array of sizeamount + 1
.
- The space complexity is O(amount) because we only need a
Example Output:
-
Input:
coins = [1, 2, 5]
,amount = 11
Output:
3
(because 11 = 5 + 5 + 1) -
Input:
coins = [2]
,amount = 3
Output:
-1
(because it’s impossible to make amount 3 with only coin 2) -
Input:
coins = [1]
,amount = 0
Output:
0
(no coins needed to make amount 0)
This dynamic programming approach is efficient and works well within the given problem constraints.