Make Exact Change Using the Fewest Notes
Solve this ProblemA cash register holds unlimited notes of several denominations. The denominations are in increasing order, the smallest is 1, and every denomination is a whole multiple of the one before it (for example 1, 4, 12, 60). Given an amount, find the fewest notes that add up to exactly that amount.
A dynamic-programming table that works out the answer for every amount up to the target is correct for any denominations, but the special multiple-of-the-previous structure allows a much simpler greedy method: repeatedly take as many of the largest note as fit.
Test Case 1:
Test Case 2:
Test Case 3:
Constraints
- ◆
1 ≤ notes.length ≤ 6; notes is strictly increasing, notes[0] = 1, and every note is a whole multiple of the previous one (for example 1, 4, 12, 60) - ◆
1 ≤ notes[i] ≤ 500 - ◆
0 ≤ amount ≤ 3000 - ◆
Any number of each note is available; return the fewest notes that add up to exactly amount (0 if amount is 0)
Try the Dry Run
Don't just read the solution — watch it execute, one step at a time.
Approach & Solutions
Brute Force — Dynamic Programming Over Every Amount
BruteBuild a table where fewest[t] is the fewest notes that make exactly t. For each total from 1 up to the target, try every note that is not larger than the total: using that note leaves total − note to be made, which the table already knows, so fewest[t] is the minimum over notes of fewest[t − note] + 1. This never assumes anything about the notes, so it is correct for any set that includes a 1 — but it fills in an entry for every amount up to the target, even though only a handful of them matter.
O(amount × notes)O(amount)1class Solution {
2 public int fewestNotes(int[] notes, int amount) {
3 int[] fewest = new int[amount + 1];
4 for (int total = 1; total <= amount; total++) {
5 fewest[total] = Integer.MAX_VALUE;
6 for (int note : notes) {
7 if (note <= total && fewest[total - note] + 1 < fewest[total]) {
8 fewest[total] = fewest[total - note] + 1;
9 }
10 }
11 }
12 return fewest[amount];
13 }
14}Optimal — Take as Many of the Largest Note as Fit, Then Move Down
OptimalBecause every note is a whole multiple of the one below it, the largest note never gets in the way: any set of smaller notes that adds up to at least the largest note can be swapped for one largest note without using more notes. So taking as many of the largest note as fit is always safe. Do that, keep the remainder, and repeat with the next note down. Each note needs one division and one remainder, so the work depends only on how many kinds of notes exist — not on the amount.
O(notes)O(1)1class Solution {
2 public int fewestNotes(int[] notes, int amount) {
3 int count = 0, remaining = amount;
4 for (int i = notes.length - 1; i >= 0; i--) {
5 count += remaining / notes[i];
6 remaining %= notes[i];
7 }
8 return count;
9 }
10}