Design an ATM Machine
MediumUpdated: Aug 2, 2025
Practice on:
Problem
There is an ATM machine that stores banknotes of 5 denominations: 20,
50, 100, 200, and 500 dollars. Initially the ATM is empty. The user can use the machine to deposit or withdraw any amount of money.
When withdrawing, the machine prioritizes using banknotes of larger values.
- For example, if you want to withdraw
$300and there are2$50banknotes,1$100banknote, and1$200banknote, then the machine will use the$100and$200banknotes. - However, if you try to withdraw
$600and there are3$200banknotes and1$500banknote, then the withdraw request will be rejected because the machine will first try to use the$500banknote and then be unable to use banknotes to complete the remaining$100. Note that the machine is not allowed to use the$200banknotes instead of the$500banknote.
Implement the ATM class:
ATM()Initializes the ATM object.void deposit(int[] banknotesCount)Deposits new banknotes in the order$20,$50,$100,$200, and$500.int[] withdraw(int amount)Returns an array of length5of the number of banknotes that will be handed to the user in the order$20,$50,$100,$200, and$500, and update the number of banknotes in the ATM after withdrawing. Returns[-1]if it is not possible (do not withdraw any banknotes in this case).
Examples
Example 1
**Input**
["ATM", "deposit", "withdraw", "deposit", "withdraw", "withdraw"]
[[], [[0,0,1,2,1]], [600], [[0,1,0,1,1]], [600], [550]]
**Output**
[null, null, [0,0,1,0,1], null, [-1], [0,1,0,0,1]]
**Explanation**
ATM atm = new ATM();
atm.deposit([0,0,1,2,1]); // Deposits 1 $100 banknote, 2 $200 banknotes,
// and 1 $500 banknote.
atm.withdraw(600); // Returns [0,0,1,0,1]. The machine uses 1 $100 banknote
// and 1 $500 banknote. The banknotes left over in the
// machine are [0,0,0,2,0].
atm.deposit([0,1,0,1,1]); // Deposits 1 $50, $200, and $500 banknote.
// The banknotes in the machine are now [0,1,0,3,1].
atm.withdraw(600); // Returns [-1]. The machine will try to use a $500 banknote
// and then be unable to complete the remaining $100,
// so the withdraw request will be rejected.
// Since the request is rejected, the number of banknotes
// in the machine is not modified.
atm.withdraw(550); // Returns [0,1,0,0,1]. The machine uses 1 $50 banknote
// and 1 $500 banknote.
Constraints
banknotesCount.length == 50 <= banknotesCount[i] <= 10^91 <= amount <= 10^9- At most
5000calls in total will be made towithdrawanddeposit. - At least one call will be made to each function
withdrawanddeposit. - Sum of
banknotesCount[i]in all deposits doesn't exceed109
Solution
Method 1 – Greedy Simulation with Largest Denomination First
Intuition
To simulate the ATM, always use the largest available banknotes first when withdrawing. For deposits, simply add the counts to the respective denominations. For withdrawals, try to use as many of the largest denomination as possible, then move to the next smaller one, and so on. If the amount cannot be formed exactly, the withdrawal fails and the ATM state is unchanged.
Approach
- Maintain an array
cntof length 5 for the count of each denomination:[20, 50, 100, 200, 500]. - For
deposit, add the deposited banknotes tocnt. - For
withdraw, starting from the largest denomination, use as many as possible without exceeding the amount or available notes. Track the notes used in a temporary array. If the amount becomes zero, updatecntand return the notes used. If not, return[-1]and do not updatecnt.
Code
Python
class ATM:
def __init__(self):
self.notes = [20, 50, 100, 200, 500]
self.cnt = [0] * 5
def deposit(self, banknotesCount: list[int]) -> None:
for i in range(5):
self.cnt[i] += banknotesCount[i]
def withdraw(self, amount: int) -> list[int]:
use = [0] * 5
for i in range(4, -1, -1):
take = min(self.cnt[i], amount // self.notes[i])
use[i] = take
amount -= take * self.notes[i]
if amount == 0:
for i in range(5):
self.cnt[i] -= use[i]
return use
return [-1]
Java
public class ATM {
private final int[] notes = {20, 50, 100, 200, 500};
private final long[] cnt = new long[5];
public ATM() {}
public void deposit(int[] banknotesCount) {
for (int i = 0; i < 5; i++) cnt[i] += banknotesCount[i];
}
public int[] withdraw(int amount) {
int[] use = new int[5];
for (int i = 4; i >= 0; i--) {
int take = (int)Math.min(cnt[i], amount / notes[i]);
use[i] = take;
amount -= take * notes[i];
}
if (amount == 0) {
for (int i = 0; i < 5; i++) cnt[i] -= use[i];
return use;
}
return new int[]{-1};
}
}
C++
class ATM {
vector<long long> cnt;
vector<int> notes = {20, 50, 100, 200, 500};
public:
ATM() : cnt(5) {}
void deposit(vector<int> banknotesCount) {
for (int i = 0; i < 5; ++i) cnt[i] += banknotesCount[i];
}
vector<int> withdraw(int amount) {
vector<int> use(5);
for (int i = 4; i >= 0; --i) {
int take = min((long long)cnt[i], amount / notes[i]);
use[i] = take;
amount -= take * notes[i];
}
if (amount == 0) {
for (int i = 0; i < 5; ++i) cnt[i] -= use[i];
return use;
}
return {-1};
}
};
Go
type ATM struct {
notes [5]int
cnt [5]int64
}
func Constructor() ATM {
return ATM{notes: [5]int{20, 50, 100, 200, 500}}
}
func (a *ATM) Deposit(banknotesCount []int) {
for i := 0; i < 5; i++ {
a.cnt[i] += int64(banknotesCount[i])
}
}
func (a *ATM) Withdraw(amount int) []int {
use := make([]int, 5)
for i := 4; i >= 0; i-- {
take := int(min(a.cnt[i], int64(amount/a.notes[i])))
use[i] = take
amount -= take * a.notes[i]
}
if amount == 0 {
for i := 0; i < 5; i++ {
a.cnt[i] -= int64(use[i])
}
return use
}
return []int{-1}
}
func min(a, b int64) int64 {
if a < b {
return a
}
return b
}