Coin Change

Fewest coins for amount = 1 + the best over amount minus each coin.

Approach

Build dp[0..amount] where dp[a] is the minimum coins to make a. For each amount, try every coin and take 1 + dp[a − coin], seeding dp[0] = 0 and everything else as infinity. The final dp[amount] is the answer, or −1 if unreachable.

Time complexity

O(amount · coins)

Space complexity

O(amount)

Common mistake

Using a greedy largest-coin-first approach — it fails for coin systems like [1, 3, 4] making 6.

Interactive walkthrough — step through it below, free and without an account

Problem

Given a collection of coin denominations and a target amount, determine the minimum number of coins needed to total that amount. You may use each denomination any number of times. Return -1 when no combination of the available coins can form the target.

Examples

Input: coins = [1, 3, 4], amount = 6

Output: 2

The best construction is 3 + 3, which uses two coins.

Input: coins = [2], amount = 3

Output: -1

Every available coin is even, so amount 3 cannot be formed.

Problem

Problem

Given a collection of coin denominations and a target amount, determine the minimum number of coins needed to total that amount. You may use each denomination any number of times. Return -1 when no combination of the available coins can form the target.

Problem and Goal

Learning goal: Translate coin combinations into a minimum-count optimization problem.

Core idea We are not looking for just any way to make the target; we want the construction with the fewest coins. Because coins may be reused, a solution can contain many copies of the same denomination. The central challenge is deciding which final coin belongs in an optimal construction.

What the answer means

For coins = [1, 3, 4] and amount = 6, the answer is 2 because 3 + 3 is better than 4 + 1 + 1, which uses three coins. If no combination reaches the target, return -1.

Algorithm plan

  • Consider every smaller amount before solving the target.
  • Record the smallest coin count known for each amount.
  • Convert an unreachable sentinel into -1 only at the end.

Micro-example

  • dp[0] = 0: making zero requires no coins.
  • For amount 3, one coin of value 3 gives dp[3] = 1.
  • For amount 6, using that result again gives dp[6] = 2.

Pitfalls

  • Do not confuse the number of combinations with the minimum number of coins.
  • The target may be zero, whose answer is 0.
  • An unreachable amount must not be treated as a valid predecessor.

Recap

  • Reuse is allowed, so earlier amounts can support later amounts.
  • The output is a minimum, not a count of all solutions.
  • Unreachable targets become -1.

Problem and Goal

Minimize coin count

For amount 6, the best construction is 3 + 3, so the minimum number of coins is 2.

Every state stores the smallest coin count found so far.

The Recurrence

Learning goal: Derive the recurrence from the identity of the final coin.

Core idea Imagine an optimal way to make amount a. Its last coin must have some denomination coin. Removing that coin leaves amount a - coin, and the remaining coins must themselves be optimal; otherwise we could improve the original solution. Therefore, try every coin that fits and keep the smallest result.

Recurrence

For every coin <= a:

dp[a] = min(dp[a], 1 + dp[a - coin])

The 1 counts the coin just added. Initialize dp[0] = 0 and every other state to infinity, represented by a value larger than any possible answer, such as amount + 1.

Key insight

The fewest coins for a equals one coin plus the best solution for a - coin, minimized over all usable coins.

Micro-example For a = 6, coin 3 examines 1 + dp[3] = 2. Coin 4 examines 1 + dp[2] = 3, and coin 1 examines 1 + dp[5] = 3; the minimum is 2.

Pitfalls

  • Only use dp[a - coin] when coin <= a.
  • Infinity must never produce a usable candidate.
  • The recurrence is a minimum, not a sum.

Recap

  • Choose the final coin conceptually.
  • Solve the leftover amount optimally.
  • Take the minimum over all denominations.

The Recurrence

Pretend `coin` is the final coin, then add one to the best answer for the remainder.

For `a = 6`, coin 3 gives `1 + dp[3] = 2`.

Bottom-Up Algorithm

Learning goal: Implement the recurrence in an order that guarantees every dependency is ready.

Core idea A state for amount a depends only on amounts smaller than a, because every usable coin is positive. That dependency direction gives a natural left-to-right fill order. By the time we compute dp[a], all possible dp[a - coin] values already exist.

Algorithm plan

  1. Create an array dp of length amount + 1.
  2. Fill it with amount + 1, acting as infinity.
  3. Set dp[0] = 0.
  4. For a from 1 through amount, try each coin.
  5. If coin <= a, update dp[a] with min(dp[a], 1 + dp[a - coin]).
  6. Return dp[amount] if it is reachable; otherwise return -1.
python
for a in range(1, amount + 1):
    for coin in coins:
        if coin <= a:
            dp[a] = min(dp[a], 1 + dp[a - coin])

Micro-example With target 6, the array begins as [0, ∞, ∞, ∞, ∞, ∞, ∞]. After processing amounts left to right, it becomes [0, 1, 2, 1, 1, 2, 2].

Pitfalls

  • Use amount + 1 or another safe sentinel, not zero.
  • Do not initialize each amount from a greedy coin choice.
  • Check the sentinel before returning the final value.

Recap

  • Increasing amounts respect all dependencies.
  • Each state tries every denomination.
  • The final state directly answers the problem.

Bottom-Up Algorithm

MethodDecision ruleReliabilityMemory
Bottom-up DPTry every coin for every amountAlways optimalO(amount)
GreedyTake the largest usable coinCan failO(1)
Brute forceExplore every combinationOptimal but slowO(amount) recursion depth

Walkthrough: Amount 6

Learning goal: Trace every one-dimensional DP state for coins = [1, 3, 4] and amount = 6.

Core idea We process amounts in increasing order and improve each state by testing all coins. The array is a compact record of solved subproblems: once dp[a] is finalized, larger amounts may reuse it. The visualization shows the best candidate after each amount is completed.

State progression

Amount aBest constructiondp[a]
0empty set0
111
21 + 12
331
441
54 + 1 or 3 + 1 + 12
63 + 32

Why the order works

Every candidate for dp[a] reads a smaller index, so left-to-right processing never reads an unknown state.

Micro-example At a = 6, the candidates are 1 + dp[5] = 3, 1 + dp[3] = 2, and 1 + dp[2] = 3. The minimum is 2.

Pitfalls

  • A state can improve after considering a later coin in the inner loop.
  • dp[4] = 1 does not imply greedy choices are globally correct.
  • Keep the array indexed by amount, not by coin position.

Recap

  • The completed array is [0, 1, 2, 1, 1, 2, 2].
  • The answer is dp[6] = 2.
  • The best combination is two coins of value 3.

Walkthrough: Amount 6

Trace the exact bottom-up computation for the canonical example [1, 3, 4], amount 6.

DP table
1 / 8
Initialize dp for amounts 0 through 6.
{
  "prev": [
    0,
    7,
    7,
    7,
    7,
    7,
    7
  ],
  "cur": [
    0,
    7,
    7,
    7,
    7,
    7,
    7
  ],
  "i": 0,
  "highlight": {
    "index": 0
  },
  "ruleUsed": "Seed dp[0] = 0 and all other states as infinity.",
  "keyIdea": "The empty amount is the only solved base case.",
  "caption": "Initialize dp for amounts 0 through 6.",
  "focus": {
    "index": 0
  },
  "delta": "dp[0] becomes 0.",
  "invariant": "All processed states represent minimum coin counts.",
  "callout": "Infinity means no construction has been found yet."
}

What does dp mean?

Rule: Seed dp[0] = 0 and all other states as infinity.

Key idea

The empty amount is the only solved base case.

Infinity means no construction has been found yet.All processed states represent minimum coin counts.
1 / 8

Pitfalls and Edge Cases

Learning goal: Recognize why greedy selection is unsafe and how the DP handles boundaries.

Core idea A greedy strategy that repeatedly takes the largest coin can make an irreversible choice before seeing the best remainder. For coins = [1, 3, 4] and amount 6, greedy chooses 4, then two 1s, using three coins. DP compares that path with the overlooked choice 3 + 3, which uses only two.

Edge-case checklist

  • Amount zero: dp[0] = 0, so return 0 immediately through the normal initialization.
  • Coin larger than the amount: skip it because a - coin would be negative.
  • Unreachable target: the sentinel remains unchanged, so return -1.
  • Repeated use: processing increasing amounts allows dp[a - coin] to include the same denomination again.

Common pitfall

Using the largest coin first fails for [1, 3, 4] and amount 6: it produces 4 + 1 + 1, not the optimum 3 + 3.

Micro-example For coins = [2], amount 3, no transition reaches dp[3]. Its sentinel survives, so the answer is -1.

Pitfalls

  • Never return the sentinel itself.
  • Never assume common coin systems make greedy universally correct.
  • Keep the base case separate from unreachable states.

Recap

  • DP explores every final-coin choice.
  • Greedy can fail even when a coin of value 1 exists.
  • Sentinel detection handles impossible targets.

Pitfalls and Edge Cases

For coins [1, 3, 4] and amount 6, why is largest-coin-first incorrect?

Complexity and Wrap-Up

Learning goal: Analyze the resource cost and summarize the reusable DP pattern.

Core idea There are amount nonzero states, and each state examines every denomination. Thus the nested loops perform roughly amount * coins.length transitions. The array stores one answer per amount, so memory grows linearly with the target.

Complexity

ResourceCostReason
TimeO(amount · coins)Every amount tries every coin
SpaceO(amount)One DP entry per amount

Here, coins denotes the number of denominations, not their numeric values. The algorithm is usually preferable to recursive brute force because overlapping subproblems are solved once and reused.

Reusable pattern

  1. Define a state for each subproblem.
  2. Seed the empty/base state.
  3. Fill states in dependency order.
  4. Take the best transition.
  5. Translate an unreachable sentinel into the requested output.

Micro-example For target 6 and three denominations, there are six nonzero states and at most eighteen coin checks. The resulting array ends with dp[6] = 2.

Pitfalls

  • Write O(amount · coins.length), not exponential time.
  • Space is O(amount), excluding the input array.
  • A sentinel is an implementation detail, not a valid answer.

Recap

  • Bottom-up DP is optimal and systematic.
  • Time is O(amount · coins); space is O(amount).
  • Return dp[amount] or -1 when unreachable.

Complexity and Wrap-Up

Visualize the per-state work and the asymptotic growth of the one-dimensional DP.

Complexity analysis
Time
O(amount · coins)
Space
O(amount)
Where the time goes
  • Create and store dpOne entry is allocated for every amount from 0 through the target.O(amount)
  • Try each coin at each amountThis nested loop dominates the running time.O(amount · coins)
  • Read final answerThe target state is already computed.O(1)
How it grows
input size n →opsO(n²)O(n log n)O(n)O(log n)O(1)

The algorithm is efficient because each amount is solved once and reused instead of exploring duplicate combinations.

Now try it on your own problem

Paste any LeetCode problem — or one of your own — and codebrew builds a walkthrough like this one for it.

Build a lesson from any problem

Related problems