Python 2043.py
class Bank:
def __init__(self, balance: List[int]):
self.size = len(balance) # = n
self.balance = [ 0 ] + balance
def transfer(self, account1: int, account2: int, money: int) -> bool:
if 1 <= account1 <= self.size and 1 <= account2 <= self.size: # and account1 != account2:
if self.balance[account1] >= money:
self.balance[account1] -= money
self.balance[account2] += money
return True
return False
def deposit(self, account: int, money: int) -> bool:
if 1 <= account <= self.size:
self.balance[account] += money
return True
return False
def withdraw(self, account: int, money: int) -> bool:
if 1 <= account <= self.size:
if self.balance[account] >= money:
self.balance[account] -= money
return True
return False
Difficulty
and has an acceptance rate of about 70% (200k+ submissions).
Typical patterns to solve this problem:
- Array
- Design
- Hash Table
- Simulation
AI Disclaimer
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.
See this dedicated page for more details.
Code Walkthrough
Overview
The provided Bank class models a simple banking system that maintains a collection of account balances and offers three fundamental operations: transferring money between accounts, depositing money into an account, and withdrawing money from an account. The implementation relies on a Python list to store balances, with an extra leading element to make the accounts 1-based, matching typical user expectations. Each public method validates input parameters before mutating the internal state, returning a Boolean flag that indicates success or failure.
Core Data Structure
The constructor receives a list of integer balances. It records the number of accounts in self.size and creates an internal list self.balance that begins with a dummy zero element followed by the supplied balances. This layout enables direct indexing using the account numbers supplied by callers.
def __init__(self, balance: List[int]):
self.size = len(balance) # total number of accounts
self.balance = [0] + balance # 1-based indexing for accounts
By storing balances in a contiguous list, the class achieves constant-time access for any account, which is essential for the high-frequency operations that a banking system typically performs.
Transfer Operation
The transfer method moves a specified amount of money from one account to another. It first checks that both account identifiers fall within the valid range (1 to self.size). The commented-out condition account1 != account2 indicates that self-transfers are implicitly allowed; the method will succeed as long as the source account has sufficient funds. After confirming that the source balance covers the requested amount, the method deducts the amount from the source and adds it to the destination, then returns True. If any validation fails, the method returns False.
def transfer(self, account1: int, account2: int, money: int) -> bool:
if 1 <= account1 <= self.size and 1 <= account2 <= self.size:
if self.balance[account1] >= money:
self.balance[account1] -= money
self.balance[account2] += money
return True
return False
The method’s early-exit pattern ensures that no state change occurs when the preconditions are not satisfied, preserving data integrity.
Deposit Operation
The deposit method adds a specified amount to a single account. It validates that the account number is within bounds and then increments the stored balance. The method always succeeds for a valid account, returning True; otherwise it returns False.
def deposit(self, account: int, money: int) -> bool:
if 1 <= account <= self.size:
self.balance[account] += money
return True
return False
Because the operation consists of a single list update, it executes in constant time.
Withdraw Operation
The withdraw method removes a specified amount from an account, provided the account exists and holds enough funds. The method first checks the account range, then verifies that the current balance meets or exceeds the withdrawal amount. If both checks pass, the balance is decreased and True is returned; otherwise the method returns False.
def withdraw(self, account: int, money: int) -> bool:
if 1 <= account <= self.size:
if self.balance[account] >= money:
self.balance[account] -= money
return True
return False
The nested condition prevents an overdraft, ensuring that the internal state never reflects a negative balance.
Edge Cases Handled
The implementation explicitly guards against several boundary conditions.
When an account identifier is less than 1 or greater than the total number of accounts, each method rejects the request, preventing out-of-range list access.
For transfer and withdraw, the code checks that the source account’s balance is at least the requested amount, thereby avoiding underflow and guaranteeing that balances remain non-negative.
The deposit method does not impose an upper bound on the amount being added, allowing arbitrarily large deposits as long as the account identifier is valid.
Because the internal list is 1-based, the dummy zero element shields the real balances from accidental modification through an index of 0.
Self-transfers (where account1 equals account2) are permitted; the method will succeed if the source balance is sufficient, effectively leaving the balance unchanged after the debit and credit steps.
Performance Optimizations
The class leverages a plain Python list for balance storage, which provides O(1) random access and update. By pre-allocating the list with a leading dummy element, the code avoids the need to adjust indices on each operation, eliminating an extra arithmetic step per call.
All three public methods employ early returns after the first failing validation, which reduces unnecessary work and keeps the execution path short.
The absence of any auxiliary data structures or loops means that each operation runs with minimal overhead, making the class well-suited for scenarios that require a large number of rapid transactions.
The Boolean return values give callers immediate feedback without raising exceptions, allowing the surrounding code to decide how to handle failures without incurring the cost of exception handling.
ELI5 - Simplified Explanation
Imagine there is a big piggy bank that holds lots of little piggy banks inside it, all lined up in a row. This code is like being the person who takes care of all those little banks. When the bank starts, it looks at how much money is already inside each one and remembers those numbers.
The first part, called transfer, is like moving coins from one bank to another. If you have enough coins in the first bank, the helper takes some out of that one and puts them into the second one for you. It checks carefully to make sure both banks are real and that the first bank has enough money to share.
Depositing is like dropping a shiny coin into a specific piggy bank. The helper just finds the one you picked and slides the extra money right in so that the piggy bank is a little bit fuller than it was before.
Withdrawing is like taking coins out of your piggy bank to go buy a toy. The helper looks to make sure that the bank really exists and that it has enough coins currently sitting inside. If there is enough money, the helper takes the amount you want out of that bank and gives it to you.
Code Quality
Complexity Analysis
Other Solutions
Obviously, I did that after I solved the problem myself.
In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.
And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.
(click on a column header to sort the table)
| author | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| author | solutions | ||||||||
| www | AlgoMonster | C++ | Python | Java | TS | ||||
| WalkCCC | C++ | Python | Java | ||||||
| leetcode.ca | C++ | Python | Java | Go | Rust | TS | |||
| Progiez | C++ | Python | Java | ||||||
| github | black-shadows | C++ | |||||||
| charles-wangkai | Java | ||||||||
| everthis | JS | ||||||||
| fsq | C++ | ||||||||
| halfrost | Go | ||||||||
| JoshCrozier | JS | ||||||||
| lkwq007 | Python | ||||||||
| suxrobGM | C# | ||||||||
| trung-hn | Python | ||||||||
| varunu28 | Java | ||||||||
| withaarzoo | C++ | ||||||||
| AlgoMonster | C++, Python, Java, TypeScript | ||||||||
| WalkCCC | C++, Python, Java | ||||||||
| leetcode.ca | C++, Go, Java, Python, Rust, TypeScript | ||||||||
| Progiez | C++, Java, Python | ||||||||
| black-shadows | C++, C++ | ||||||||
| charles-wangkai | Java | ||||||||
| everthis | JavaScript | ||||||||
| fsq | C++ | ||||||||
| halfrost | Go | ||||||||
| JoshCrozier | JavaScript | ||||||||
| lkwq007 | Python | ||||||||
| suxrobGM | C# | ||||||||
| trung-hn | Python | ||||||||
| varunu28 | Java | ||||||||
| withaarzoo | C++ |
Videos
Solved On The Same Day
- problem 1072: Flip Columns For Maximum Number of Equal Rows
- problem 2074: Reverse Nodes in Even Length Groups
- problem 2091: Removing Minimum and Maximum From Array
- problem 2517: Maximum Tastiness of Candy Basket
Extra
- Tech Stack - my development environment and tools
- AI - how AI helped me create this website (NOT solving the problems)
- Progress - progression over time
- Quality - code quality