title: Lemonade Change
slug: lemonade-change
difficulty: easy
leetcode_id: 860
leetcode_url: https://leetcode.com/problems/lemonade-change/
categories:
  - arrays
patterns:
  - greedy

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 i<sup>th</sup> 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

    &nbsp;

    **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

    &nbsp;

    **Step 3: Return the result**

    - If we process all customers successfully, return `true`

    &nbsp;

    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.
