Dynamic Programming · Medium

204. Coin Change - Minimum Number of Coins

Topics: Dynamic Programming

Solve it on DeVert Campus - free code runner

Problem

Given n coin denominations (unlimited supply of each) and a target amount, find the minimum number of coins needed to make exactly that amount, or print -1 if it can't be made.

Input and output

Input: Three lines: n (number of denominations); n space-separated denominations; the target amount. Output: Print a single integer - the minimum number of coins to make the amount exactly, or -1 if it's impossible.

Example

Input:
3
1 2 5
11
Output:
3

Constraints

1 <= n <= 100, 0 <= amount <= 10^5

Key observation

This is the MINIMIZATION sibling of 'Coin Change - Count Number of Ways' - despite sounding similar, they need genuinely different DP structures (this one takes a MIN over coin choices per amount; the counting version processes coins one at a time across all amounts to avoid overcounting).

Intuition

Find the minimum number of coins needed to make a target amount, with unlimited supply of given denominations. Brute force: Try every possible combination of coins directly (recursively including/excluding each denomination any number of times) - this recomputes the SAME sub-amounts repeatedly, causing exponential blowup without memoization. Optimised: Since dp[a] only depends on smaller sub-amounts (a minus some coin value), building the table bottom-up ensures every sub-amount's minimum is computed exactly once and reused directly by all larger amounts that need it.

Approach 1

Recursively try every coin denomination at each step, subtracting it from the remaining amount and recursing, taking the minimum number of coins over all choices that eventually reach exactly zero, and treating a negative remainder or exhausted attempts as impossible. This mirrors the problem definition exactly, but without any caching, the same remaining-amount subproblem gets explored again and again through different combinations of coin choices, causing exponential growth in the number of recursive calls. Time: exponential Space: O(amount)

Optimal - Bottom-Up Iterative DP

Fill an array dp[0..amount] iteratively from smallest to largest, where dp[0] = 0 and dp[a] is the minimum over all denominations c <= a of 1 + dp[a - c], reading previously computed smaller entries directly instead of recursing. This computes exactly the same values as the memoized version, but with amount allowed up to 10^5, a recursive solution risks overflowing the call stack on that much recursion depth, whereas the iterative bottom-up version has no such risk and also avoids the overhead of function calls entirely. Time: O(n*amount) Space: O(amount)

Better - Top-Down Memoized Recursion

Use the same recursive structure as brute force, trying every denomination at each remaining amount, but cache the minimum number of coins needed for each distinct remaining amount the first time it is computed. Since there are only 'amount + 1' distinct remaining-amount subproblems, caching collapses the exponential recursion tree of brute force down to a linear number of unique subproblems, each taking O(n) work to try all denominations. Time: O(n*amount) Space: O(amount)

Step by step

1. dp[a] = minimum coins needed to make amount a; dp[0]=0. 2. For each amount a, try every coin c <= a: dp[a] = min(dp[a], dp[a-c] + 1). 3. If dp[amount] remains unreachable after filling the table, print -1.

Complexity

Time: O(n * amount) - for each of the amount values, trying all n coin denominations. Space: O(amount), for the dp array.

Edge cases

Test amount = 0 (0 coins needed), an amount that can't be formed from the given denominations (print -1), and amount = 10^5 (upper bound) for the DP array's size.

Interview tip

Be ready to explicitly note that greedy (always use the largest coin that fits) does NOT always give the minimum for ARBITRARY denomination sets (e.g. {1,3,4} for amount 6: greedy gives 4+1+1=3 coins, but optimal is 3+3=2) - this is exactly why DP, not greedy, is needed in general.

All DSA problems