Skip to main content

Minimum Coins

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:

    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
    Example 3:

    Input: coins = [1], amount = 0
    Output: 0


Solution: Memization​

class Solution {
public:
// Recursive function with memoization
int f(int index, vector<int> &coins, int amount, vector<vector<int>> &dp){
// Base case: if only one coin type
if(index == 0){
if(amount % coins[index] == 0)
return amount / coins[index];
else
return 1e9; // impossible
}

// If already computed
if(dp[index][amount] != -1) return dp[index][amount];

// Don't take the current coin
int notTake = f(index - 1, coins, amount, dp);

// Take the coin if it's <= amount
int take = 1e9;
if(coins[index] <= amount){
take = 1 + f(index, coins, amount - coins[index], dp);
}

// Store and return min of take/not-take
return dp[index][amount] = min(take, notTake);
}

int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<vector<int>> dp(n, vector<int>(amount + 1, -1));
int result = f(n - 1, coins, amount, dp);
return (result >= 1e9) ? -1 : result;
}
};



Solution: Tabulation​

class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<vector<int>> dp(n, vector<int>(amount + 1, 0));

// Initialize base case (row 0)
for(int rem = 0; rem <= amount; rem++){
if(rem % coins[0] == 0){
dp[0][rem] = rem / coins[0];
}
else
dp[0][rem] = 1e9;
}

for(int i = 1; i < n; i++){
for(int target = 0; target <= amount; target++){
int notTake = dp[i - 1][target];
int take = 1e9;

if(coins[i] <= target){
take = 1 + dp[i][target - coins[i]];
}

dp[i][target] = min(take, notTake);
}
}
int result = dp[n-1][amount];
return result >= 1e9 ? -1 : result;
}
};



Solution: Space Optimized​

class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
int n = coins.size();
vector<int> prev(amount + 1, 0);

// Initialize base row
for(int rem = 0; rem <= amount; rem++){
if(rem % coins[0] == 0){
prev[rem] = rem / coins[0];
}
else
prev[rem] = 1e9;
}

for(int i = 1; i < n; i++){
vector<int> curr(amount + 1, 0);
for(int target = 0; target <= amount; target++){
int notTake = prev[target];
int take = 1e9;

if(coins[i] <= target){
take = 1 + curr[target - coins[i]];
}

curr[target] = min(take, notTake);
}
prev = curr;
}
int result = prev[amount];
return result >= 1e9 ? -1 : result;
}
};


✅ How It Works​

  • We are given coin denominations and a target amount.
  • We must use the fewest number of coins to make up that amount.
  • We apply dynamic programming to build solutions from smaller subproblems.
  • We have three options: memoization, tabulation, and space optimization.

🧩 Key Formula​

cpp
CopyEdit
dp[i][amt] = min(dp[i-1][amt], 1 + dp[i][amt - coins[i]]) if coins[i] <= amt


⏱️ Time & Space Complexity​

ApproachTimeSpace
Memoization (Top-Down)O(n * amount)O(n * amount)
TabulationO(n * amount)O(n * amount)
Space OptimizedO(n * amount)O(amount)

⚠️ Edge Cases​

  • amount = 0: Always 0 coins.
  • No combination adds up: Return 1.
  • Coins contain 1: Will always find a solution.
  • All denominations larger than amount.

💡 Other Approaches​

ApproachTime Complexity
Recursion only ❌Exponential
Memoization ✅O(n * amount)
Tabulation ✅O(n * amount)
Space Optimized ✅O(n * amount)

  • Coin Change 2 – Count number of ways to make amount.
  • Unbounded Knapsack – Classic variation.
  • Minimum Number of Jumps
  • Subset Sum Variants
🚀 Level Up Your Engineering Mindset

Never Study in Isolation. Join Binary Dose.

Connect with fellow engineers, clear conceptual doubts, and get 2 visual breakdowns & engineering mental models daily across our community channels.

Discord
Official Hub

Discord Community

Start at #welcome-and-rules, say hello in #general-chat, clear doubts, and collaborate with engineers worldwide.

Join Discord Server→
⚡
Daily Knowledge Drops

Daily Visual Deep-Dives

Bite-sized system design schematics, core OS internals, and DSA intuition served right into your feeds every single day.

💡Have handwritten notes, cheat-sheets, or want to publish a technical article?
Learn How to Contribute→