Jump to section

Coin Change asks for the fewest coins needed to make a given amount, using as many coins of each value as you like, or -1 if it cannot be done. The standard solution is bottom-up dynamic programming: work out the fewest coins for every amount from 0 upwards, each one built from a smaller amount plus one coin. It runs in O(amount ร— number of coins) time and O(amount) space.

The Problem

You are given a list of coin values and a target amount. You can use each coin value as many times as you like. Return the smallest number of coins that add up exactly to the amount, or -1 if no combination works.

Example 1

Input: coins = [1, 2, 5], amount = 11
Output: 3
Why: 5 + 5 + 1 = 11 uses three coins, and no two coins reach 11.

Example 2

Input: coins = [2], amount = 3
Output: -1
Why: only even totals can be made from 2s.

Assumptions to confirm

  • Can each coin value be used more than once? (Yes, as often as you like, in the classic version.)
  • What does amount 0 return? (0 coins.)
  • Are coin values positive? (Assume yes.)
  • Do you want the count or the coins themselves? (The count; listing the coins is a follow-up.)

Start With the Brute Force

The natural first idea is greedy: always take the largest coin that fits. It works for everyday currencies, so say why it fails in general. With coins [1, 3, 4] and amount 6, greedy takes 4 + 1 + 1 (three coins), but 3 + 3 uses two.

The correct brute force tries every coin at every step, recursively: the answer for an amount is 1 plus the best answer for the amount minus each coin. That is exponential, because the same smaller amounts are solved again and again. Recognising those repeated subproblems is exactly what leads to dynamic programming.

Ready to put this into practice?

Practice this with MockIF →

Still applying for jobs? Let Auto Apply do it

The Optimal Approach: Bottom-Up Dynamic Programming

1

Define the subproblem

dp[a] is the fewest coins needed to make amount a.

2

Set the base case

dp[0] = 0. Every other amount starts at a sentinel that means "not reachable yet", such as amount + 1.

3

Fill the table from small to large

For each amount a, try every coin no larger than a: dp[a] = min(dp[a], dp[a - coin] + 1).

4

Read the answer

If dp[amount] is still the sentinel, return -1; otherwise return dp[amount].

Solution in Python and TypeScript

Both versions use amount + 1 as the "impossible" value: you can never need more coins than the amount itself when the smallest coin is 1, so anything larger means unreachable.

Python

def coin_change(coins: list[int], amount: int) -> int:
    INF = amount + 1  # more coins than could ever be needed
    dp = [0] + [INF] * amount  # dp[a] = fewest coins to make a
    for a in range(1, amount + 1):
        for coin in coins:
            if coin <= a and dp[a - coin] + 1 < dp[a]:
                dp[a] = dp[a - coin] + 1
    return dp[amount] if dp[amount] != INF else -1

TypeScript

function coinChange(coins: number[], amount: number): number {
  const INF = amount + 1; // more coins than could ever be needed
  const dp = new Array<number>(amount + 1).fill(INF); // dp[a] = fewest coins to make a
  dp[0] = 0;
  for (let a = 1; a <= amount; a++) {
    for (const coin of coins) {
      if (coin <= a && dp[a - coin] + 1 < dp[a]) dp[a] = dp[a - coin] + 1;
    }
  }
  return dp[amount] === INF ? -1 : dp[amount];
}

The top-down version, a recursive function with a memo, gives the same complexity and is often easier to explain first. Bottom-up avoids deep recursion for large amounts.

Ready to put this into practice?

Practice this with MockIF →

Still applying for jobs? Let Auto Apply do it

Time and Space Complexity

ApproachTimeSpaceWhen to use it
Greedy (largest coin first)O(amount)O(1)Only for coin systems known to be greedy-safe
Plain recursionExponentialO(amount) stackOnly as your first spoken answer
Recursion with a memoO(amount ร— coins)O(amount)Easy to derive from the recursion
Bottom-up tableO(amount ร— coins)O(amount)The expected interview answer

How to Talk Through Coin Change in an Interview

  1. Clarify: "Can I reuse each coin value? Count or the coins themselves? What if it is impossible?"
  2. Brute force: "Greedy fails for coins like 1, 3, 4. The safe brute force tries every coin recursively, but solves the same amounts many times."
  3. Optimise: "I will solve every amount from 0 up and reuse smaller answers. Each amount is the best of one more coin on top of a smaller amount."
  4. Code: explain the sentinel value and the -1 at the end.
  5. Test: [1, 2, 5] with 11, [2] with 3, and amount 0. State O(amount × coins) time and O(amount) space.

Ready to put this into practice?

Practice this with MockIF →

Still applying for jobs? Let Auto Apply do it

Edge Cases and Common Follow-Ups

Amount 0

Return 0 without any coins.

Unreachable amounts

Return -1. Using a sentinel bigger than any real answer keeps the min comparison simple.

Count the ways instead

Coin Change II asks how many combinations make the amount. Loop over coins in the outer loop so each combination is counted once.

List the coins used

Store which coin improved each dp[a], then walk back from the amount.

Very large amounts

Ask about limits. Breadth-first search over amounts is an alternative that stops as soon as the amount is reached.

Practise Coin Change in a Mock Coding Round

Reading a solution is not the same as producing one with someone listening. The gap shows up as long silences, a jump straight to code without a brute force, or a bug you only spot after the interviewer asks you to test. The fix is to rehearse problems like Coin Change out loud, under time pressure, while explaining each decision.

MockIF runs mock coding interviews with a voice AI interviewer in a real in-browser editor, in Python and TypeScript. It runs your code against tests, asks you to explain your approach, adds follow-up questions the way a real interviewer would, and then scores your answer and gives specific feedback. Each session costs 2 credits. It is free to start with 5 credits, then monthly or 3-monthly plans, or one-off credit packs (see pricing).

Frequently Asked Questions

Why does the greedy approach fail for coin change?
Taking the biggest coin first is not always optimal. With coins 1, 3 and 4 and amount 6, greedy uses 4 + 1 + 1 while 3 + 3 needs only two coins.
What is the time complexity of the coin change DP?
O(amount ร— number of coins), because every amount up to the target tries every coin once. Space is O(amount) for the table.
What is the difference between Coin Change and Coin Change II?
Coin Change asks for the fewest coins. Coin Change II asks how many different combinations reach the amount, which changes the recurrence and the loop order.
Should I write it top-down or bottom-up?
Either is fine. Top-down with a memo is often easier to derive from the recursion; bottom-up avoids recursion limits. Say which one you chose and why.
Why use amount + 1 as the impossible value?
No real answer can exceed the amount when coins are positive integers, so amount + 1 safely means "not reachable" and still works with min.

Stop Preparing in Your Head. Start Practicing Out Loud.

Drop your resume, add a job description, and get a mock interview like the real thing.

Start Free Mock Interview →
No credit card required. 5 free credits to start.

Still applying for jobs? Let Auto Apply do it for you.

Try Auto Apply →