2Brute2Best
πŸ”₯0

Lemonade Change

EasyΒ·LeetCode #860Basic Anchor
LeetCode
30-Second Mental ModelLocal Feasibility β€” running balance with a greedy choice for $20 change
Complexity:O(2^N)β†’O(N)
Key Insight

Keep two counters, fives and tens. A 5 adds a five. A 10 takes a five and adds a ten. For a 20, spend a 10 and a 5 whenever you can, and use three 5s only when there is no $10 to spend. If neither works, return false.

Core Validity Invariant

A 20 customer can be served only if the drawer holds a 10 and a 5, or three 5s. A 10 customer can be served only if the drawer holds a 5.

01

Problem

A lemonade costs 5. Customers line up one at a time, and each pays with a 5, 10 or 20 bill. You start with no money in the drawer.

Each customer must leave having paid exactly $5, so if they pay more, you must hand back the difference right away. Return true if you can give every customer the right change in order, and false if at some point you cannot.

Input

An array bills, where bills[i] is the bill that customer i pays with. Every value is 5, 10 or 20.

Output

true if every customer can get the right change, otherwise false.

Example 1
Input: bills = [5, 5, 5, 10, 20]
Output: true

The first three customers pay 5, so the drawer holds three 5 bills. The fourth pays 10 and gets a 5 back. The fifth pays 20 and gets a 10 and a $5 back.

Example 2
Input: bills = [5, 5, 10, 10, 20]
Output: false

After four customers the drawer holds two 10 bills and no 5 bill. The last customer needs 15 back, and two 10s cannot make that.

Constraints
  • β€’ 1 ≀ bills.length ≀ 10^5
  • β€’ Each bill is 5, 10 or 20.
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck β€” each hint is counted.

  1. 1.

    To give change to the next customer, what do you need to know about the drawer right now?

  2. 2.

    A 5 bill can pay any change, but a 10 bill can only ever be handed out as part of a $20's change. Does that difference matter?

  3. 3.

    For a 20 customer, how many different ways are there to hand back 15?

  4. 4.

    If you had to choose one way for a $20, which one would leave you with the most options for later customers?

  5. 5.

    Do you really need the full list of bills in the drawer, or is a count of each kind enough?

03

Brute force approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceRecurse, trying 10 + 5 and 5 + 5 + 5 at each $20 billO(2^N)O(N)
OptimalKeep two counters; for a $20 use a $10 and a $5 when possibleO(N)O(1)
09

Why does this belong to this pattern?

Clues in the problem statement
  • β€œchange for every customer, in order”Each step depends on what is left in the drawer, so we walk the bills left to right and keep a running balance.
  • β€œbills of $5, $10 and $20”Only three bill types, so a count for each of the two change bills is enough. There is no need to store the drawer.
  • β€œreturn true or false”We only need to know whether anyone gets stuck, so one failure is enough to stop.
Running balance (drawer)+fails when a customer cannot be given change+keep the most flexible bills→Local Feasibility — running balance with a greedy choice for $20 change

This is a running balance question. The drawer must never run short, and it changes by one step per customer. What makes it different from a plain balance check is the choice for a $20: the two ways to make 15 leave different drawers. The greedy picks the one that keeps the most useful money, the 5s. In Candy and Gas Station there is no such choice to make.

10

Don't make this mistake

Pattern confusion: smallest bills first
βœ— if (fives >= 3) { fives -= 3; // three $5s first } else if (tens > 0 && fives > 0) { tens--; fives--; }
βœ“ if (tens > 0 && fives > 0) { tens--; fives--; // a $10 and a $5 first } else if (fives >= 3) { fives -= 3; }

This looks like making change with as few small coins as possible, but the rule is about keeping the most useful money. With bills = [5, 5, 5, 5, 10, 20, 10], the wrong order pays the 20 with 5 + 5 + 5. That leaves no 5 and one 10, so the last 10 customer cannot get change and the answer is false. The right order pays 10 + 5 and keeps two $5s, so the answer is true.

Forgetting that a $10 stays in the drawer
βœ— if (bill == 10) { fives--; // the $10 is not stored }
βœ“ if (bill == 10) { fives--; tens++; }

Without tens++, the 10 disappears and a later 20 cannot use it. With bills = [5, 5, 10, 20], the right answer is true: the 10 takes a 5 back, and the 20 is paid as 10 + 5. The buggy version has no 10 for the 20, needs three 5s, has only one, and returns false.

Not checking for change on a $10 customer
βœ— if (bill == 10) { fives--; // fives may go negative tens++; }
βœ“ if (bill == 10) { if (fives == 0) return false; fives--; tens++; }

If no $5 is in the drawer, the counter goes negative and later checks read nonsense. With bills = [10, 5, 5, 5, 5, 20], the first customer cannot get change, so the answer is false. Without the check, the counters are fives = βˆ’1, then fives = 3 at the $20, and the code returns true.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like Greedy translate into production architectures and low-level memory mechanics.