Facebook Pixel

860. Lemonade Change

Problem Description

You're running a lemonade stand where each lemonade costs $5. Customers line up to buy lemonade one at a time, in the order they appear in the input array. Each customer buys exactly one lemonade and pays with either a $5, $10, or $20 bill.

Your task is to determine if you can make correct change for every customer. You start with no money in your cash register.

The key constraints are:

  • Each lemonade costs exactly $5
  • Customers can pay with $5, $10, or $20 bills
  • You must give correct change to each customer (so they effectively pay $5)
  • You start with no bills for making change
  • You can only use bills received from previous customers to make change

For example:

  • If a customer pays with $5, you don't need to give change
  • If a customer pays with $10, you need to give back $5
  • If a customer pays with $20, you need to give back $15 (which could be three $5 bills or one $10 and one $5)

Given an array bills where bills[i] represents the bill the i-th customer uses to pay, return true if you can successfully provide correct change to all customers, or false if at any point you cannot make the correct change.

The solution tracks the number of $5 and $10 bills available. When making change for a $20 bill, it prioritizes using one $10 and one $5 bill (if available) over using three $5 bills, as this preserves more $5 bills for future transactions.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that we only need to track the bills we receive, not the total money. Since each lemonade costs $5, we're essentially managing a change-making system.

Let's think through what happens with each type of payment:

  • When someone pays with $5: Perfect! No change needed, and we gain a $5 bill for future use
  • When someone pays with $10: We need to return $5, so we must have at least one $5 bill available
  • When someone pays with $20: We need to return $15 in change

For the $20 case, we have two options for making $15 change:

  1. Give one $10 bill + one $5 bill
  2. Give three $5 bills

This leads to an important strategic decision: when we have both options available, which should we choose? The greedy approach suggests using option 1 (one $10 + one $5) whenever possible. Why? Because $5 bills are more versatile - they're needed for making change for both $10 and $20 bills, while $10 bills are only useful for $20 bills.

We don't need to track $20 bills at all because they're too large to be useful for making change (we never need to give back $20 or more).

The solution naturally emerges: maintain counters for $5 and $10 bills. Process each customer in order, updating our bill inventory and checking if we have enough bills to make change. If at any point we can't make change (particularly when our $5 bill count goes negative), we return false. If we successfully serve all customers, we return true.

Learn more about Greedy patterns.

Solution Approach

The implementation uses a greedy algorithm with simple counter variables to track our available bills.

We initialize two counters:

  • five: tracks the number of $5 bills we have
  • ten: tracks the number of $10 bills we have

We process each customer's payment in order:

Case 1: Customer pays with $5

  • No change needed
  • Increment five counter by 1

Case 2: Customer pays with $10

  • Need to give back $5 in change
  • Increment ten counter by 1 (we receive a $10 bill)
  • Decrement five counter by 1 (we give back a $5 bill)

Case 3: Customer pays with $20

  • Need to give back $15 in change
  • We apply the greedy strategy:
    • If we have at least one $10 bill available (if ten:), give back one $10 and one $5:
      • Decrement ten by 1
      • Decrement five by 1
    • Otherwise, give back three $5 bills:
      • Decrement five by 3

After handling each customer, we check if five < 0. If it is, we couldn't make proper change for this customer, so we immediately return false.

If we successfully process all customers without the five counter going negative, we return true.

The algorithm runs in O(n) time where n is the number of customers, and uses O(1) space since we only maintain two counter variables regardless of input size.

Ready to land your dream job?

Unlock your dream job with a 3-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with the input bills = [5, 5, 10, 10, 20].

We start with five = 0 and ten = 0 (no bills in our cash register).

Customer 1 pays with $5:

  • No change needed
  • Update: five = 1, ten = 0
  • We now have one $5 bill

Customer 2 pays with $5:

  • No change needed
  • Update: five = 2, ten = 0
  • We now have two $5 bills

Customer 3 pays with $10:

  • Need to give back $5 in change
  • We receive a $10 bill: ten = 1
  • We give back a $5 bill: five = 2 - 1 = 1
  • Update: five = 1, ten = 1
  • Check: five >= 0 โœ“ (we successfully made change)

Customer 4 pays with $10:

  • Need to give back $5 in change
  • We receive a $10 bill: ten = 2
  • We give back a $5 bill: five = 1 - 1 = 0
  • Update: five = 0, ten = 2
  • Check: five >= 0 โœ“ (we successfully made change)

Customer 5 pays with $20:

  • Need to give back $15 in change
  • Greedy decision: Since ten > 0, we prefer giving one 10+one10 + one 5
  • We give back one $10 bill: ten = 2 - 1 = 1
  • We give back one $5 bill: five = 0 - 1 = -1
  • Update: five = -1, ten = 1
  • Check: five < 0 โœ— (we cannot make change!)

Since five < 0 after Customer 5, we return false. We don't have enough $5 bills to make proper change for the last customer.

Solution Implementation

1class Solution:
2    def lemonadeChange(self, bills: List[int]) -> bool:
3        # Initialize counters for $5 and $10 bills
4        five_dollar_count = 0
5        ten_dollar_count = 0
6      
7        # Process each customer's payment
8        for bill in bills:
9            if bill == 5:
10                # Customer pays with $5, no change needed
11                five_dollar_count += 1
12            elif bill == 10:
13                # Customer pays with $10, need to give $5 change
14                ten_dollar_count += 1
15                five_dollar_count -= 1
16            else:  # bill == 20
17                # Customer pays with $20, need to give $15 change
18                if ten_dollar_count > 0:
19                    # Prefer giving one $10 and one $5 as change
20                    ten_dollar_count -= 1
21                    five_dollar_count -= 1
22                else:
23                    # Give three $5 bills as change
24                    five_dollar_count -= 3
25          
26            # Check if we have enough change
27            if five_dollar_count < 0:
28                return False
29      
30        # Successfully provided change to all customers
31        return True
32
1class Solution {
2    /**
3     * Determines if we can provide correct change for all customers in a lemonade stand.
4     * Each lemonade costs $5. Customers can pay with $5, $10, or $20 bills.
5     * We start with no change and must give correct change to each customer in order.
6     * 
7     * @param bills Array of bills representing the payment from each customer in order
8     * @return true if we can provide change to all customers, false otherwise
9     */
10    public boolean lemonadeChange(int[] bills) {
11        // Track the count of $5 and $10 bills we have as change
12        int fiveDollarBills = 0;
13        int tenDollarBills = 0;
14      
15        // Process each customer's payment
16        for (int bill : bills) {
17            switch (bill) {
18                case 5:
19                    // Customer pays exact amount, no change needed
20                    fiveDollarBills++;
21                    break;
22                  
23                case 10:
24                    // Customer pays $10, need to give $5 change
25                    tenDollarBills++;
26                    fiveDollarBills--;
27                    break;
28                  
29                case 20:
30                    // Customer pays $20, need to give $15 change
31                    // Prefer giving one $10 and one $5 if possible
32                    if (tenDollarBills > 0) {
33                        tenDollarBills--;
34                        fiveDollarBills--;
35                    } else {
36                        // Otherwise, give three $5 bills
37                        fiveDollarBills -= 3;
38                    }
39                    break;
40            }
41          
42            // Check if we have enough change after serving this customer
43            if (fiveDollarBills < 0) {
44                return false;
45            }
46        }
47      
48        return true;
49    }
50}
51
1class Solution {
2public:
3    bool lemonadeChange(vector<int>& bills) {
4        // Track the count of $5 and $10 bills we have for making change
5        int fiveDollarCount = 0;
6        int tenDollarCount = 0;
7      
8        // Process each customer's payment
9        for (int bill : bills) {
10            if (bill == 5) {
11                // Customer pays with $5, no change needed
12                fiveDollarCount++;
13            } 
14            else if (bill == 10) {
15                // Customer pays with $10, need to give $5 change
16                tenDollarCount++;
17                fiveDollarCount--;
18            } 
19            else {  // bill == 20
20                // Customer pays with $20, need to give $15 change
21                if (tenDollarCount > 0) {
22                    // Prefer to give one $10 and one $5
23                    tenDollarCount--;
24                    fiveDollarCount--;
25                } else {
26                    // Give three $5 bills as change
27                    fiveDollarCount -= 3;
28                }
29            }
30          
31            // Check if we have enough bills to make change
32            if (fiveDollarCount < 0) {
33                return false;
34            }
35        }
36      
37        return true;
38    }
39};
40
1/**
2 * Determines if we can provide correct change to every customer in line
3 * @param bills - Array of bill values ($5, $10, or $20) representing customer payments
4 * @returns true if we can make change for every customer, false otherwise
5 */
6function lemonadeChange(bills: number[]): boolean {
7    // Track count of $5 and $10 bills available for making change
8    let fiveDollarBills: number = 0;
9    let tenDollarBills: number = 0;
10  
11    // Process each customer's payment
12    for (const bill of bills) {
13        switch (bill) {
14            case 5:
15                // Customer pays exact amount, no change needed
16                fiveDollarBills++;
17                break;
18              
19            case 10:
20                // Customer needs $5 change
21                fiveDollarBills--;
22                tenDollarBills++;
23                break;
24              
25            case 20:
26                // Customer needs $15 change
27                if (tenDollarBills > 0) {
28                    // Prefer giving one $10 and one $5
29                    tenDollarBills--;
30                    fiveDollarBills--;
31                } else {
32                    // Give three $5 bills if no $10 bills available
33                    fiveDollarBills -= 3;
34                }
35                break;
36        }
37      
38        // Check if we have enough bills to make change
39        if (fiveDollarBills < 0) {
40            return false;
41        }
42    }
43  
44    return true;
45}
46

Time and Space Complexity

Time Complexity: O(n), where n is the length of the bills array. The algorithm iterates through the bills array exactly once, performing constant-time operations (arithmetic operations and comparisons) for each bill.

Space Complexity: O(1). The algorithm uses only two integer variables (five and ten) to keep track of the count of 5and5 and 10 bills, regardless of the input size. No additional data structures that scale with input size are used.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Not Checking for Negative Bills After Each Transaction

The Pitfall: A common mistake is only checking if you have enough bills before making change, rather than verifying the count remains valid after the transaction. Some implementations might check if five_dollar_count >= 1 before giving change but forget to verify the result isn't negative afterward.

Why It Happens: Developers might assume that checking availability beforehand is sufficient, but when dealing with $20 bills, you might need either 1 or 3 five-dollar bills depending on ten-dollar availability, making pre-checks complex.

Solution: Always check if five_dollar_count < 0 after processing each bill. This unified check handles all cases elegantly:

for bill in bills:
    # ... process bill ...
  
    # Single check after each transaction
    if five_dollar_count < 0:
        return False

2. Incorrect Greedy Strategy for $20 Bills

The Pitfall: When making change for a 20bill,somemightprioritizeusingthree20 bill, some might prioritize using three 5 bills to preserve $10 bills, or might not consider both options at all:

# Wrong approach - always uses $5 bills first
if bill == 20:
    if five_dollar_count >= 3:
        five_dollar_count -= 3
    elif ten_dollar_count >= 1 and five_dollar_count >= 1:
        ten_dollar_count -= 1
        five_dollar_count -= 1

Why It Matters: 5billsaremoreversatileโˆ’theyโ€ฒreneededformakingchangeforboth5 bills are more versatile - they're needed for making change for both 10 and 20bills.20 bills. 10 bills can only be used for 20bills.Usinga20 bills. Using a 10 bill when possible preserves more $5 bills for future transactions.

Solution: Always try to use one 10andone10 and one 5 first, falling back to three $5 bills only when necessary:

if bill == 20:
    if ten_dollar_count > 0:
        # Prefer this option to preserve $5 bills
        ten_dollar_count -= 1
        five_dollar_count -= 1
    else:
        # Fallback when no $10 bills available
        five_dollar_count -= 3

3. Forgetting to Track Received Bills

The Pitfall: Only decrementing bills when making change but forgetting to increment when receiving them:

# Wrong - forgets to add received bills to inventory
if bill == 10:
    five_dollar_count -= 1  # Gives change but doesn't add the $10

Why It Happens: Focus on the "making change" aspect can overshadow the fact that you're also receiving bills that become part of your available change.

Solution: Remember to update your bill inventory for received payments:

if bill == 10:
    ten_dollar_count += 1    # Add the received $10
    five_dollar_count -= 1    # Give $5 as change

4. Over-complicating with $20 Bill Tracking

The Pitfall: Some solutions unnecessarily track $20 bills:

twenty_dollar_count = 0  # Unnecessary
if bill == 20:
    twenty_dollar_count += 1  # Not needed

Why It's Wrong: 20billscanneverbeusedaschange(changeamountsareonly20 bills can never be used as change (change amounts are only 5 or $15), so tracking them wastes space and adds complexity.

Solution: Only track bills that can be used as change - 5and5 and 10 bills. Ignore $20 bills after processing them.

Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which of the tree traversal order can be used to obtain elements in a binary search tree in sorted order?


Recommended Readings

Want a Structured Path to Master System Design Too? Donโ€™t Miss This!

Load More