Coin Change
Solve this ProblemTest Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ coins.length ≤ 15 - ◆
1 ≤ coins[i] ≤ 100 - ◆
0 ≤ amount ≤ 1000
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Recursive Without Memoization
BruteReaching a remaining amount of 0 takes 0 more coins — that's the finish line. For any positive amount still owed, try every coin denomination as the next one used: each choice reduces the amount by that coin's value and costs one coin, so the best count from here is 1 plus whatever the best count turns out to be for the reduced amount. Since coins can be reused freely, the same coin can be tried again immediately in the next call. An amount that goes negative, or that no combination can ever reach, is treated as impossible and excluded from the comparison; the smallest count found across every coin tried is the answer for that amount.
O(coins^amount)O(amount)1class Solution {
2 private int[] coins;
3
4 public int coinChange(int[] coins, int amount) {
5 this.coins = coins;
6 int result = solve(amount);
7 return result == Integer.MAX_VALUE ? -1 : result;
8 }
9
10 private int solve(int remaining) {
11 if (remaining == 0) return 0;
12 if (remaining < 0) return Integer.MAX_VALUE;
13 int best = Integer.MAX_VALUE;
14 for (int c : coins) {
15 int sub = solve(remaining - c);
16 if (sub != Integer.MAX_VALUE) best = Math.min(best, 1 + sub);
17 }
18 return best;
19 }
20}Optimal — Bottom-Up 1D DP
OptimalTrack, for every amount from 0 up to the target, the fewest coins needed to make it exactly — starting from dp[0] = 0 coins needed for nothing. For every later amount, trying each coin denomination that fits gives a candidate count: 1 plus whatever the fewest coins is for the amount left over after using that coin, provided that smaller amount is itself reachable at all. The smallest candidate across every coin becomes that amount's answer. Because smaller amounts are always filled in before larger ones need them, every lookup is already resolved, and the entry at the full amount holds the final answer — or stays unreachable if no combination of coins ever lands on it exactly.
O(coins.length × amount)O(amount)1class Solution {
2 public int coinChange(int[] coins, int amount) {
3 int[] dp = new int[amount + 1];
4 Arrays.fill(dp, Integer.MAX_VALUE);
5 dp[0] = 0;
6 for (int a = 1; a <= amount; a++) {
7 for (int c : coins) {
8 if (c <= a && dp[a - c] != Integer.MAX_VALUE) {
9 dp[a] = Math.min(dp[a], dp[a - c] + 1);
10 }
11 }
12 }
13 return dp[amount] == Integer.MAX_VALUE ? -1 : dp[amount];
14 }
15}