title: Lemonade Change slug: lemonade-change difficulty: easy leetcode_id: 860 leetcode_url: https://leetcode.com/problems/lemonade-change/ categories: - arrays patterns: - greedy function_signature: "def lemonade_change(bills: list[int]) -> bool:" test_cases: visible: - input: { bills: [5, 5, 5, 10, 20] } expected: true - input: { bills: [5, 5, 10, 10, 20] } expected: false hidden: - input: { bills: [5] } expected: true - input: { bills: [10] } expected: false - input: { bills: [5, 5, 10] } expected: true - input: { bills: [5, 5, 5, 5, 20, 20] } expected: true - input: { bills: [5, 5, 5, 10, 5, 20, 5, 10, 5, 20] } expected: true - input: { bills: [5, 5, 10, 20, 5, 5, 5, 5, 5, 5, 5, 5, 5, 10, 5, 5, 20, 5, 20, 5] } expected: true description: | At a lemonade stand, each lemonade costs `$5`. Customers are standing in a queue to buy from you and order one at a time (in the order specified by `bills`). Each customer will only buy one lemonade and pay with either a `$5`, `$10`, or `$20` bill. You must provide the correct change to each customer so that the net transaction is that the customer pays `$5`. Note that you do not have any change in hand at first. Given an integer array `bills` where `bills[i]` is the bill the ith customer pays, return `true` *if you can provide every customer with the correct change*, or `false` *otherwise*. constraints: | - `1 <= bills.length <= 10^5` - `bills[i]` is either `5`, `10`, or `20` examples: - input: "bills = [5,5,5,10,20]" output: "true" explanation: "From the first 3 customers, we collect three $5 bills. From the fourth customer, we collect a $10 bill and give back a $5. From the fifth customer, we give a $10 bill and a $5 bill. Since all customers got correct change, we output true." - input: "bills = [5,5,10,10,20]" output: "false" explanation: "From the first two customers, we collect two $5 bills. For the next two customers, we collect a $10 bill and give back a $5 bill each. For the last customer, we cannot give the change of $15 back because we only have two $10 bills (no $5 bills left)." explanation: intuition: | Imagine you're actually running a lemonade stand with a cash register. You start with an empty register and customers line up to pay. The key insight is that **$5 bills are the most valuable** — not because of their face value, but because they're the most *versatile* for making change. A $5 bill can be used to: - Give change for a $10 bill (need one $5) - Give change for a $20 bill (need one $10 + one $5, OR three $5s) Think of it like this: when a customer pays with $20, you have two options for the $15 change: 1. One $10 + one $5 (preferred — uses the less versatile $10) 2. Three $5 bills (backup — depletes your precious $5s) The greedy choice is always to **preserve your $5 bills** when possible. Use $10 bills first when giving change for $20, because $10 bills can only be used for one purpose (change for $20), while $5 bills can be used for both $10 and $20 transactions. approach: | We solve this using a **Greedy Simulation**: **Step 1: Initialise counters** - `fives`: Count of $5 bills in hand, starts at `0` - `tens`: Count of $10 bills in hand, starts at `0` - We don't need to track $20 bills — they can never be used as change   **Step 2: Process each customer in order** - **If customer pays $5**: No change needed. Increment `fives` by 1 - **If customer pays $10**: Need to give $5 change. If `fives == 0`, return `false`. Otherwise, decrement `fives`, increment `tens` - **If customer pays $20**: Need to give $15 change. Try the greedy choice first: - If we have at least one $10 and one $5: use them (decrement both) - Else if we have at least three $5s: use them (decrement `fives` by 3) - Else: return `false` — we can't make change   **Step 3: Return the result** - If we process all customers successfully, return `true`   The greedy strategy works because using a $10 bill when available always leaves us in a better (or equal) position than using three $5 bills. common_pitfalls: - title: Not Prioritising $10 Bills for $20 Change description: | When giving change for $20, some might randomly choose between using three $5s or one $10 + one $5. This can lead to failure. For example, with `bills = [5,5,10,20,5,5,5,10,20,20]`: - If you use three $5s for the first $20 instead of $10 + $5, you might run out of $5 bills later when a $10 customer arrives Always prefer using $10 bills for $20 change — $5 bills are more versatile. wrong_approach: "Random or first-available bill selection" correct_approach: "Greedy: prefer $10 + $5 over three $5s" - title: Tracking $20 Bills description: | It's tempting to track all bill types, but $20 bills are useless for making change. You can never give a $20 bill back to a customer (since the most change needed is $15). Tracking $20 bills wastes space and adds unnecessary complexity. wrong_approach: "Maintaining a counter for $20 bills" correct_approach: "Only track $5 and $10 bills" - title: Forgetting the Empty Register Start description: | The problem states you start with no change. If the first customer pays with anything other than $5, you immediately fail. For input `bills = [10,5,5,5,5]`, the answer is `false` because you can't give change to the very first customer. wrong_approach: "Assuming some initial change is available" correct_approach: "Start with fives = 0 and tens = 0" key_takeaways: - "**Greedy pattern**: When multiple valid choices exist, prefer the one that keeps more options open (preserve $5 bills)" - "**Simulation**: Sometimes the best approach is to simulate the process step by step" - "**Track only what matters**: $20 bills are never used as change, so don't track them" - "**Order matters**: The greedy choice ($10 + $5 over three $5s) ensures we handle future customers optimally" time_complexity: "O(n). We process each customer exactly once with O(1) operations per customer." space_complexity: "O(1). We only use two integer counters (`fives` and `tens`) regardless of input size." solutions: - approach_name: Greedy Simulation is_optimal: true code: | def lemonade_change(bills: list[int]) -> bool: # Track only $5 and $10 bills (we never use $20 for change) fives = 0 tens = 0 for bill in bills: if bill == 5: # No change needed, just collect the $5 fives += 1 elif bill == 10: # Need to give $5 change if fives == 0: return False # Can't make change fives -= 1 tens += 1 else: # bill == 20 # Need to give $15 change # Greedy: prefer using $10 + $5 to preserve $5 bills if tens > 0 and fives > 0: tens -= 1 fives -= 1 elif fives >= 3: fives -= 3 else: return False # Can't make change return True # Successfully served all customers explanation: | **Time Complexity:** O(n) — Single pass through the bills array. **Space Complexity:** O(1) — Only two counters used. We simulate serving each customer, making the greedy choice to preserve $5 bills when possible. The key insight is that $10 + $5 is always preferred over three $5s for $20 change, because $5 bills are needed for both $10 and $20 transactions while $10 bills are only useful for $20 transactions. - approach_name: Brute Force Simulation is_optimal: false code: | def lemonade_change(bills: list[int]) -> bool: # Track all bills (including $20, though unnecessary) cash = {5: 0, 10: 0, 20: 0} for bill in bills: cash[bill] += 1 # Receive payment change_needed = bill - 5 # Try to make change using largest bills first for denomination in [20, 10, 5]: while change_needed >= denomination and cash[denomination] > 0: change_needed -= denomination cash[denomination] -= 1 if change_needed > 0: return False # Couldn't make exact change return True explanation: | **Time Complexity:** O(n) — Still linear, but with more operations per customer. **Space Complexity:** O(1) — Fixed-size dictionary. This approach uses a general change-making algorithm: try to use the largest bills first. While it works, it's unnecessarily complex for this specific problem. It also tracks $20 bills (which are never used) and uses a loop where direct conditionals suffice. The greedy simulation above is cleaner and more efficient in practice.