Skip to content

Commit e89cee1

Browse files
committed
chore: add daily leetcode post 2241. Design an ATM Machine
1 parent d7dd2ee commit e89cee1

File tree

1 file changed

+111
-0
lines changed

1 file changed

+111
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
---
2+
title: 2241. Design an ATM Machine.md
3+
date: '2025-01-06'
4+
tags:
5+
- - Python
6+
- - Answer
7+
abbrlink: a21411f
8+
---
9+
10+
# QUESTION:
11+
12+
[2241. Design an ATM Machine.md](https://leetcode.cn/problems/design-an-atm-machine/description/?envType=daily-question&envId=2025-01-05)
13+
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.
14+
15+
When withdrawing, the machine prioritizes using banknotes of larger values.
16+
17+
For example, if you want to withdraw $300 and there are 2 $50 banknotes, 1 $100 banknote, and 1 $200 banknote, then the machine will use the $100 and $200 banknotes.
18+
However, if you try to withdraw $600 and there are 3 $200 banknotes and 1 $500 banknote, then the withdraw request will be rejected because the machine will first try to use the $500 banknote and then be unable to use banknotes to complete the remaining $100. Note that the machine is not allowed to use the $200 banknotes instead of the $500 banknote.
19+
Implement the ATM class:
20+
21+
ATM() Initializes the ATM object.
22+
void deposit(int[] banknotesCount) Deposits new banknotes in the order $20, $50, $100, $200, and $500.
23+
int[] withdraw(int amount) Returns an array of length 5 of 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).
24+
25+
# My Think:
26+
27+
The purpose of this question is to simulate an ATM machine, which returns the amount of money you withdraw, no more and no less. I am greedy, because the second sentence "There are 3 `$200` bills and 1 `$500` bill in the machine, so the withdrawal request will be rejected"
28+
This shows that we can skip thinking about the knapsack problem in complex dynamic programming and directly consider simple greed.
29+
30+
Because the denominations of the deposited money are only `20`, `50`, `100`, `200`, `500`, we can store them in the list in advance and wait for traversal.
31+
32+
Then we create a `defaultdict()` to create a hash table for each denomination in the ATM machine.
33+
34+
`deposit()` creates a reverse traversal dictionary. Because we need to traverse the dictionary from large denominations to small denominations, the reverse dictionary is very convenient at this time.
35+
36+
Assuming the initial `amount` is `600`, the first denomination traversed is `500`, It fits the logic of the question very well
37+
38+
For the `withdraw()` function, I created a temporary dictionary deep copy storage so that the initial array will not be changed when `[-1]` is returned. Otherwise, it will be troublesome to backtrack.
39+
40+
Here, Sylvia and I used two different traversal methods. She traversed the list of denominations, while I traversed the dictionary directly (actually traversed the key directly).
41+
42+
1. If the current denomination (`600`) is greater than the current denomination (`500`), then try to deduct it. If the bank money is withdrawn directly, then look at the next denomination.
43+
44+
2. If it is not withdrawn, then `amount` deducts the deductible share and then continues to look at the next denomination.
45+
46+
3. If there is still `amount` left at the end, return `[-1]`, otherwise calculate how many bills have been consumed in total, which is the answer.
47+
48+
这道题的目的是模拟一台ATM机器, 让你取多少钱, 就返回多少钱, 不能多也不能少. 我是贪心的思想, 因为第二句"机器里有 3 张 `$200` 的钞票和1 张 `$500` 的钞票,那么取款请求会被拒绝"
49+
这就说明我们可以跳过思考复杂的动态规划中的背包问题, 而直接考虑简单的贪心.
50+
51+
因为存的钱的面额只有`20`, `50`, `100`, `200`, `500` 这五种面额, 于是我们提前存在列表里面等待遍历即可.
52+
然后我们创建一个`defaultdict()`, 为ATM机器里面的每种面额创建哈希表.
53+
54+
`deposit()`创建了一个反向遍历的字典. 因为我们需要从大面额到小面额遍历字典, 在这个时候反向的字典就很方便.
55+
56+
假设初始`amount`为`600`, 遍历到的第一个面额就是`500`, 就很符合题目的逻辑
57+
58+
`withdraw()`函数, 我之所以创建了一个临时字典深拷贝储存是在返回`[-1]`的情况下不更改初始数组. 否则还要回溯挺麻烦的.
59+
60+
这里我和Sylvia用了两种不同的遍历方式, 她遍历了面额的列表, 而我是直接遍历的字典(实际上直接遍历的key).
61+
62+
1. 如果当前面额(`600`)大于了当前面额(`500`), 那就尝试扣除, 如果直接把银行钱取完了, 那再看下一个面值.
63+
2. 如果没有取完, 那么`amount`扣除掉能扣除的份额, 再继续看下一个面额即可.
64+
3. 到最后`amount`还有剩余则返回`[-1]`, 否则计算一共消耗了多少张钞票, 即是答案了.
65+
66+
# Code:
67+
68+
```python
69+
import copy
70+
from typing import List
71+
72+
from collections import defaultdict
73+
74+
75+
class ATM:
76+
77+
def __init__(self):
78+
self.sd = defaultdict(int)
79+
self.amount = ['20', '50', '100', '200', '500']
80+
81+
def deposit(self, banknotesCount: List[int]) -> None:
82+
for i in range(len(banknotesCount) - 1, -1, -1):
83+
self.sd[self.amount[i]] += banknotesCount[i]
84+
85+
86+
87+
def withdraw(self, amount: int) -> List[int]:
88+
tempSd = copy.deepcopy(self.sd)
89+
# key = 面值, value = 张数
90+
for key, value in tempSd.items():
91+
if amount >= int(key) and value > 0:
92+
# 需要多少张钞票
93+
howManyPiece = amount // int(key)
94+
if howManyPiece >= value:
95+
# 全部取出来
96+
tempSd[key] = 0
97+
amount -= value * int(key)
98+
else:
99+
# 取出这么多钞票
100+
tempSd[key] -= howManyPiece
101+
amount -= int(key) * howManyPiece
102+
else:
103+
if amount > 0:
104+
return [-1]
105+
else:
106+
ans = []
107+
for i in self.sd.keys():
108+
ans.append(self.sd[i] - tempSd[i])
109+
self.sd = copy.deepcopy(tempSd)
110+
return ans[::-1]
111+
```

0 commit comments

Comments
 (0)