Your Dashboard
Interview Coaching
Learn
System Design
ML System Design
Code
Behavioral
Salary Negotiation
Interview Guides
Leetcode 2043. Simple Bank System
Asked at:
Coinbase
Paypal
Capital One
DESCRIPTION
Design a Bank class that manages 1-indexed account balances and supports three core operations: transfer(account1, account2, money), deposit(account, money), and withdraw(account, money). Each operation must validate account indices and ensure sufficient funds for withdrawals/transfers, returning true on success (with balance updates) or false on failure. For example, if account 1 has $100 and you call transfer(1, 2, 50), account 1 should have $50 and account 2 should have $50 more.
Input:
Output:
Explanation: Initialize 2 accounts. Deposit $100 to account 1 (balance: $100). Withdraw $50 from account 1 (balance: $50). Transfer $30 from account 1 to account 2 (balances: account 1 = $20, account 2 = $30).
Constraints:
- 1 <= n <= 10^5 (number of accounts)
- 1 <= account, account1, account2 <= n (valid account indices)
- 1 <= money <= 10^14 (transaction amount)
- At most 10^4 calls to transfer, deposit, and withdraw
- Accounts are 1-indexed (first account is index 1, not 0)
Understanding the Problem
The core challenge is implementing a stateful banking system that tracks multiple account balances while enforcing validation rules on every operation. You must handle 1-indexed accounts (a common source of off-by-one errors) and ensure atomic operations where invalid transactions don't partially modify state. The key design decision is choosing an appropriate data structure to store balances efficiently while supporting O(1) lookups and updates.
Building Intuition
A naive approach might use a dictionary with account numbers as keys, but this wastes space for dense account ranges. A better approach uses an array/list to store balances, mapping 1-indexed accounts to 0-indexed array positions (balance[account - 1]). For example, if n=3, initialize [0, 0, 0] and access account 2's balance via balance[1].
This pattern appears in financial systems, resource allocation, and inventory management where you need to track multiple entities with unique identifiers. Understanding index mapping (1-indexed to 0-indexed) and validation-before-mutation prevents critical bugs in production systems. The design also teaches encapsulation by hiding internal array indexing from the public API.
Common Pitfalls
Implementation
Class Initialization and Balance Storage
Initialize the Bank class with n accounts, storing balances in a 0-indexed array of size n (all starting at $0). The constructor maps 1-indexed account numbers to 0-indexed array positions by subtracting 1. For example, Bank(3) creates balance = [0, 0, 0] where account 1's balance is at balance[0]. This provides O(1) access for all operations while maintaining the 1-indexed public API.
class Bank:def __init__(self, balance: list[int]):"""Initialize bank with n accounts (1-indexed API, 0-indexed storage).:param balance: List of initial balances for accounts 1 to n"""self.balance = balance[:]self.n = len(balance)
Deposit and Withdraw Operations
Implement deposit(account, money) to add funds and withdraw(account, money) to remove funds with validation. Both must check if 1 <= account <= n (valid index) before accessing the array. Withdraw additionally checks balance[account - 1] >= money (sufficient funds) before deducting. For example, withdraw(2, 50) on balance = [100, 30, 0] fails (returns false) because account 2 only has $30.
def deposit(self, account: int, money: int) -> bool:if 1 <= account <= self.n:self.balance[account - 1] += moneyreturn Truereturn Falsedef withdraw(self, account: int, money: int) -> bool:if 1 <= account <= self.n and self.balance[account - 1] >= money:self.balance[account - 1] -= moneyreturn Truereturn False
Transfer Operation with Dual Validation
Implement transfer(account1, account2, money) by validating both accounts exist and source has sufficient funds before modifying any state. The operation is atomic: either both balances update or neither does. For example, transfer(1, 4, 50) with n=3 returns false (account 4 doesn't exist) without touching account 1's balance. Only after all checks pass do you execute balance[account1 - 1] -= money and balance[account2 - 1] += money.
def transfer(self, account1: int, account2: int, money: int) -> bool:# Validate both accounts exist (1-indexed)if account1 < 1 or account1 > len(self.balance):return Falseif account2 < 1 or account2 > len(self.balance):return False# Validate source has sufficient fundsif self.balance[account1 - 1] < money:return False# Atomic update: both balances change togetherself.balance[account1 - 1] -= moneyself.balance[account2 - 1] += moneyreturn True
What We've Learned
- Pattern: Use array indexing with offset (`array[id - 1]`) to map 1-indexed IDs to 0-indexed storage efficiently
- Validation: Always validate before mutate to ensure atomic operations and prevent invalid state transitions
- Use Case: Applies to account systems, resource pools, and entity managers where IDs start at 1 but internal storage is 0-indexed
Problems to Practice
medium
Related problem that helps practice similar concepts and patterns.
Question Timeline
See when this question was last asked and where, including any notes left by other candidates.
Mid October, 2025
Capital One
Senior
Mid September, 2025
Paypal
Senior
Mid September, 2025
Capital One
Senior
Comments
Hello Interview Premium
Your account is free and you can post anonymously if you choose.