860. Lemonade Change
Problem Description
In this problem, you are operating a lemonade stand where each glass of lemonade is sold for $5
. You start without any change in hand. Customers come in a queue, and you should sell them lemonade in the order they come, with each customer buying exactly one glass. Customers pay with a $5
, $10
, or $20
bill. Your task is to determine whether you can provide the correct change to each customer using the bills you have at your disposal. You need to give back the net difference such that each customer effectively pays exactly $5
for their lemonade. For instance, if a customer pays with $20
, and you have enough change, you will hand back $15
in change. If it is possible to provide the correct change for all customers, the function should return true
, otherwise it should return false
.
Intuition
The main issue is to always have enough $5
bills to make change, since they are the cornerstone of all transactions. Here's the intuitive approach:
- Keep track of the number of
$5
and$10
bills (we don't need to track$20
bills as they don't help in making change). - Process each customer in the queue one by one and handle the payment.
- If a customer pays with a
$5
bill, no change is needed, and you just increase your count of$5
bills. - If a customer pays with a
$10
bill, you need to give back a$5
as change, so you decrement the$5
bill count and increment the$10
bill count. - If a customer pays with a
$20
bill, you prefer to give back one$10
and one$5
as change because this uses up larger bills and keeps more$5
bills for future transactions (which are more crucial). If you can't give change in this combination, you attempt to give three$5
bills as change.
- If a customer pays with a
- After handling a transaction, if the count of
$5
bills is negative, that means you didn't have enough change for a customer, and hence you should returnfalse
. - If you finish processing all customers and never ran out of
$5
bills, then you returntrue
.
Learn more about Greedy patterns.
Solution Approach
The solution is straightforward and follows a greedy algorithmic approach, which operates on the simplest of principles: give out the minimal amount of change necessary.
In terms of data structures, we only need two variables to keep track of the number of $5
and $10
bills as these are the only denominations we can give out for change.
The algorithm goes as follows:
- Initialize two variables:
five
andten
to track the count of$5
and$10
bills we have. We do not need to keep track of$20
bills as they cannot be given as change. - Iterate through each bill in the
bills
list.- If the bill is
$5
, increment thefive
counter, since we now have an additional$5
bill. - If the bill is
$10
, we need to give a$5
bill as change, so we decrement thefive
counter and increment theten
counter. - If the bill is
$20
, firstly, we check if we have any$10
bills:- If we have a
$10
bill, we use it along with a$5
bill to make$15
in change (decrement bothten
andfive
). - If we don't have a
$10
bill, we need to give out three$5
bills (decrementfive
by three).
- If we have a
- After handling the bill, we check if the
five
counter has gone negative. If it has, it means we can't make change for the current transaction, and we returnfalse
.
- If the bill is
- After the loop, if we've successfully given change to every customer, our
five
counter should never be negative, and we can returntrue
.
The algorithm effectively balances between preserving $5
bills, which are necessary for giving change to customers who pay with $10
and $20
, and using up $10
bills when possible to avoid depleting the $5
bills too quickly. This greedy strategy works for any sequence of bills because making change with larger bills when possible is always at least as good as, and often better than, breaking down $5
bills.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach. Suppose we have a queue of customers with the following bills: 10, 5, $10.
- Initialize
five
= 0 andten
= 0. - Customer 1 pays with $5:
five
is incremented by 1 (five
= 1,ten
= 0).
- Customer 2 pays with $10:
- We give one $5 bill as change:
five
is decremented by 1,ten
is incremented by 1 (five
= 0,ten
= 1).
- We give one $5 bill as change:
- Customer 3 pays with $20:
- To give change, we'd prefer a 5 bill. We have one $10 bill:
ten
is decremented by 1 andfive
is decremented by 1 to provide $15 in change (five
= -1,ten
= 0).- Since we don't have any $5 bills left to give as change, we cannot fulfill this transaction - we return
false
.
- To give change, we'd prefer a 5 bill. We have one $10 bill:
We stop the process as we've been unable to provide change for the third customer. Thus, the function will return false
in this example.
Solution Implementation
1class Solution:
2 def lemonadeChange(self, bills: List[int]) -> bool:
3 # Initialize counters for five and ten dollar bills
4 five_dollar_count = ten_dollar_count = 0
5
6 # Iterate over each bill received
7 for bill in bills:
8 if bill == 5:
9 # If it's a $5 bill, simply increase the count of $5 bills
10 five_dollar_count += 1
11 elif bill == 10:
12 # If it's a $10 bill, give one $5 bill as change
13 ten_dollar_count += 1
14 five_dollar_count -= 1
15 else:
16 # If it's a $20 bill, try to give one $10 and one $5 as change if possible
17 # Otherwise, give three $5 bills as change
18 if ten_dollar_count:
19 ten_dollar_count -= 1
20 five_dollar_count -= 1
21 else:
22 five_dollar_count -= 3
23
24 # If at any point the count of $5 bills drops below zero, it's impossible to give change
25 if five_dollar_count < 0:
26 return False
27
28 # If we got to the end without running out of $5 bills, we can give change for all transactions
29 return True
30
1class Solution {
2 public boolean lemonadeChange(int[] bills) {
3 // Initialize counters for five and ten dollar bills
4 int fiveDollarBills = 0;
5 int tenDollarBills = 0;
6
7 // Iterate over each bill in the array
8 for (int bill : bills) {
9 // Use switch-case to handle different bill values
10 switch (bill) {
11 case 5:
12 // If it's a $5 bill, no change is needed, increase count of $5 bills
13 fiveDollarBills++;
14 break;
15 case 10:
16 // For a $10 bill, we need to give one $5 bill as change
17 tenDollarBills++; // Increase $10 bills
18 fiveDollarBills--; // Reduce $5 bills as we give it as change
19 break;
20 case 20:
21 // For a $20 bill, prefer to give one $10 and one $5 as change if possible
22 if (tenDollarBills > 0) {
23 tenDollarBills--; // Use a $10 bill for change
24 fiveDollarBills--; // Use a $5 bill for change
25 } else {
26 // If no $10 bills, we need to give three $5 bills as change
27 fiveDollarBills -= 3;
28 }
29 break;
30 }
31 // If at any point we do not have enough $5 bills to give as change, return false
32 if (fiveDollarBills < 0) {
33 return false;
34 }
35 }
36 // If we can make change for all customers, return true
37 return true;
38 }
39}
40
1#include <vector> // Include the vector header for using the vector container.
2
3class Solution {
4public:
5 // Method to determine if we can provide every customer with correct change.
6 bool lemonadeChange(vector<int>& bills) {
7 // Initialize counters for $5 and $10 bills.
8 int fiveDollarBills = 0, tenDollarBills = 0;
9
10 // Iterate over each bill in the vector 'bills'.
11 for (int bill : bills) {
12 if (bill == 5) {
13 // If the bill is $5, no change is needed, simply increment $5 bill counter.
14 ++fiveDollarBills;
15 } else if (bill == 10) {
16 // If the bill is $10, give one $5 bill as change and increment $10 bill counter.
17 ++tenDollarBills;
18 --fiveDollarBills; // Giving change of one $5 bill.
19 } else {
20 // For a $20 bill, prefer to give one $10 and one $5 bill as change if possible.
21 if (tenDollarBills > 0) {
22 --tenDollarBills;
23 --fiveDollarBills; // Giving change of one $10 and one $5 bill.
24 } else {
25 // If no $10 bills are available, give three $5 bills as change.
26 fiveDollarBills -= 3;
27 }
28 }
29
30 // If at any point we do not have enough $5 bills to give change, return false.
31 if (fiveDollarBills < 0) {
32 return false;
33 }
34 }
35 // If we were able to provide change for all customers, return true.
36 return true;
37 }
38};
39
1function lemonadeChange(bills: number[]): boolean {
2 // Initialize the count of $5 and $10 bills
3 let fiveDollarBills = 0;
4 let tenDollarBills = 0;
5
6 // Iterate through each bill received
7 for (let bill of bills) {
8 switch (bill) {
9 case 5: // When the bill is $5, no change is needed, simply increase the count of $5 bills
10 fiveDollarBills++;
11 break;
12 case 10: // For a $10 bill, give back one $5 bill as change and increase $10 bill count
13 fiveDollarBills--; // Giving change
14 tenDollarBills++; // Receiving $10
15 break;
16 case 20: // For a $20 bill, try to give one $10 and one $5 as change if possible
17 if (tenDollarBills > 0) {
18 tenDollarBills -= 1; // Giving one $10 bill as change
19 bill -= 10; // $10 change has been given, need $10 more
20 }
21 fiveDollarBills -= bill / 5 - 1; // Give the rest of the change in $5 bills
22 break;
23 // Note: Though the use of the 'bill' variable here is a bit unconventional,
24 // since we've subtracted $10 if we've used a $10 bill for change,
25 // dividing 'bill' by 5 now effectively gives us how many more $5 bills
26 // we need to give as change (either one $5 bill if we gave a $10, or
27 // three $5 bills if we didn't).
28 }
29
30 // If we don't have enough $5 bills to give change, return false
31 if (fiveDollarBills < 0) {
32 return false;
33 }
34 }
35
36 // If we've iterated through all bills and always had enough to give change, return true
37 return true;
38}
39
Time and Space Complexity
Time Complexity:
The given algorithm iterates through the list of bills once. During each iteration, it performs a constant number of operations such as comparison, increment, and decrement on integer variables. These operations do not depend on the size of the input and hence take constant time.
Therefore, the time complexity of the algorithm is determined by the number of iterations, which is directly proportional to the length of the list of bills, n
. Hence, the time complexity is O(n)
, where n
is the length of the bills list.
Space Complexity:
The algorithm uses a fixed number of integer variables (five
and ten
) to keep track of the count of 10 bills. The space used does not grow with the size of the input list. These two integer variables use a constant amount of space.
Consequently, the space complexity of the algorithm is O(1)
, which means it uses constant additional space regardless of the input size.
Learn more about how to find time and space complexity quickly using problem constraints.
Depth first search is equivalent to which of the tree traversal order?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Don’t Miss This!