Talentd
FleetCode
Make and follow sheets.Sign in

Simple Bank System solution and explanation

MediumArrayDesignHash TableSimulation7 min read69.7% acceptanceUpdated 9 Apr 2026
Simple Bank System | Easy Simulation| Leetcode 2043 | codestorywithMIKcodestorywithMIK · 11:08 · 5K viewsWatch on YouTube
9 more videos on this problem
  1. Simple Bank System | Easy Simulation| Leetcode 2043 | codestorywithMIKcodestorywithMIK · 11:08 · 5K views
  2. Leetcode Solution - 2043 Simple Bank SystemJohn Leonardo · 4:58 · 1K views
  3. 2043. Simple Bank System (Leetcode Medium)Programming Live with Larry · 10:17 · 1K views
  4. 2043. Simple Bank System | Leetcode Daily - PythonLeetcode Daily · 9:21 · 760 views
  5. Daily Leetcode #2035: Oct 26, 2025 - 2043. Simple Bank SystemProgramming Live with Larry · 10:42 · 591 views
  6. Simple Bank System | LeetCode 2043 | Java Code | Developer CoderDeveloper Coder · 14:22 · 448 views
  7. Simple Bank System | Leetcode 2043 | Design ProblemSanyam IIT Guwahati · 10:22 · 442 views
  8. Simple Bank System | Leetcode 2043 | DSA | Code With Deepak | Hindi Explanation | Data StructureCode with Deepak · 5:15 · 395 views
  9. Simple Bank System | LeetCode 2043 - Pythonimpoldev · 5:58 · 262 views
  10. 2043 Simple Bank System Leetcode CPP SolutionAnimated Anand · 6:51 · 233 views

The problem

You have been tasked with writing a program for a popular bank that will automate all its incoming transactions (transfer, deposit, and withdraw). The bank has n accounts numbered from 1 to n. The initial balance of each account is stored in a 0-indexed integer array balance, with the (i + 1)th account having an initial balance of balance[i].

Execute all the valid transactions. A transaction is valid if:

  • The given account number(s) are between 1 and n, and
  • The amount of money withdrawn or transferred from is less than or equal to the balance of the account.

Implement the Bank class:

  • Bank(long[] balance) Initializes the object with the 0-indexed integer array balance.
  • boolean transfer(int account1, int account2, long money) Transfers money dollars from the account numbered account1 to the account numbered account2. Return true if the transaction was successful, false otherwise.
  • boolean deposit(int account, long money) Deposit money dollars into the account numbered account. Return true if the transaction was successful, false otherwise.
  • boolean withdraw(int account, long money) Withdraw money dollars from the account numbered account. Return true if the transaction was successful, false otherwise.

Example 1:

Input
["Bank", "withdraw", "transfer", "deposit", "transfer", "withdraw"]
[[[10, 100, 20, 50, 30]], [3, 10], [5, 1, 20], [5, 20], [3, 4, 15], [10, 50]]
Output
[null, true, true, true, false, false]

Explanation
Bank bank = new Bank([10, 100, 20, 50, 30]);
bank.withdraw(3, 10);    // return true, account 3 has a balance of $20, so it is valid to withdraw $10.
                         // Account 3 has $20 - $10 = $10.
bank.transfer(5, 1, 20); // return true, account 5 has a balance of $30, so it is valid to transfer $20.
                         // Account 5 has $30 - $20 = $10, and account 1 has $10 + $20 = $30.
bank.deposit(5, 20);     // return true, it is valid to deposit $20 to account 5.
                         // Account 5 has $10 + $20 = $30.
bank.transfer(3, 4, 15); // return false, the current balance of account 3 is $10,
                         // so it is invalid to transfer $15 from it.
bank.withdraw(10, 50);   // return false, it is invalid because account 10 does not exist.

Constraints:

  • n == balance.length
  • 1 <= n, account, account1, account2 <= 105
  • 0 <= balance[i], money <= 1012
  • At most 104 calls will be made to each function transfer, deposit, withdraw.

Approach overview

Problem Overview: You need to design a simple banking system that stores balances for n accounts and supports three operations: transfer, deposit, and withdraw. Each operation must validate account numbers and ensure sufficient balance before modifying the stored amounts.

Approach 1: Direct Array Manipulation (O(1) per operation, O(n) space)

The most straightforward design stores account balances in an array where the index represents the account number. Every operation performs constant-time access using direct indexing. For example, a transfer checks if both accounts exist, verifies that the source account has enough funds, then subtracts from one index and adds to the other.

This approach works because arrays provide O(1) random access. Validation simply checks if the account index falls within the valid range. Deposits increment the balance at the target index, while withdrawals subtract after confirming sufficient funds. The implementation stays clean and efficient since each operation touches only a few array positions.

This design aligns well with problems involving fixed-size collections and predictable identifiers. When account IDs map directly to indices, arrays are faster and simpler than extra data structures. Concepts here closely relate to array operations and straightforward simulation of system behavior.

Approach 2: HashMap for Account Balances (O(1) average per operation, O(n) space)

A more flexible design stores balances in a HashMap where the key is the account number and the value is the balance. Each operation performs constant-time average lookups using a hash table. Before modifying balances, the system checks whether the relevant keys exist in the map.

Transfers involve two hash lookups followed by updates to both accounts. Deposits update the value for the target account, while withdrawals check the stored balance before subtracting. HashMap-based storage removes reliance on contiguous indices and works even if account numbers are sparse or dynamically created.

This design demonstrates common system design patterns where entities are mapped to values using a hash table. It becomes useful when identifiers are not guaranteed to align with array indices or when the system might expand dynamically.

Recommended for interviews: The array-based implementation is typically expected because the problem provides account balances in order and account numbers map directly to positions. It shows you recognize the simplest constant-time design. The HashMap approach still demonstrates good understanding of scalable system modeling and hash-based lookups.

Approach 1: Direct Array Manipulation

This approach uses a simple array to store the balance of each account starting from account 1 at index 0. All operations check for validity by ensuring accounts fit within valid range and ensuring sufficient funds for transactions before modifying the array accordingly.

class Bank:
    def __init__(self, balance):
        self.balance = balance

    def transfer(self, account1, account2, money):
        if account1 <= 0 or account1 > len(self.balance) or account2 <= 0 or account2 > len(self.balance):
            return False
        if self.balance[account1 - 1] < money:
            return False
        self.balance[account1 - 1] -= money
        self.balance[account2 - 1] += money
        return True

    def deposit(self, account, money):
        if account <= 0 or account > len(self.balance):
            return False
        self.balance[account - 1] += money
        return True

    def withdraw(self, account, money):
        if account <= 0 or account > len(self.balance) or self.balance[account - 1] < money:
            return False
        self.balance[account - 1] -= money
        return True
class Bank {
    private long[] balance;
    
    public Bank(long[] balance) {
        this.balance = balance;
    }
    
    public boolean transfer(int account1, int account2, long money) {
        if (account1 <= 0 || account1 > balance.length || account2 <= 0 || account2 > balance.length) return false;
        if (balance[account1 - 1] < money) return false;
        balance[account1 - 1] -= money;
        balance[account2 - 1] += money;
        return true;
    }
    
    public boolean deposit(int account, long money) {
        if (account <= 0 || account > balance.length) return false;
        balance[account - 1] += money;
        return true;
    }
    
    public boolean withdraw(int account, long money) {
        if (account <= 0 || account > balance.length || balance[account - 1] < money) return false;
        balance[account - 1] -= money;
        return true;
    }
}
#include <vector>

class Bank {
public:
    std::vector<long> balance;
    
    Bank(std::vector<long>& balance) : balance(balance) {}
    
    bool transfer(int account1, int account2, long money) {
        if (account1 <= 0 || account1 > balance.size() || account2 <= 0 || account2 > balance.size()) return false;
        if (balance[account1 - 1] < money) return false;
        balance[account1 - 1] -= money;
        balance[account2 - 1] += money;
        return true;
    }
    
    bool deposit(int account, long money) {
        if (account <= 0 || account > balance.size()) return false;
        balance[account - 1] += money;
        return true;
    }
    
    bool withdraw(int account, long money) {
        if (account <= 0 || account > balance.size() || balance[account - 1] < money) return false;
        balance[account - 1] -= money;
        return true;
    }
};
class Bank {
    constructor(balance) {
        this.balance = balance;
    }
    
    transfer(account1, account2, money) {
        if (account1 <= 0 || account1 > this.balance.length || account2 <= 0 || account2 > this.balance.length) return false;
        if (this.balance[account1 - 1] < money) return false;
        this.balance[account1 - 1] -= money;
        this.balance[account2 - 1] += money;
        return true;
    }
    
    deposit(account, money) {
        if (account <= 0 || account > this.balance.length) return false;
        this.balance[account - 1] += money;
        return true;
    }
    
    withdraw(account, money) {
        if (account <= 0 || account > this.balance.length || this.balance[account - 1] < money) return false;
        this.balance[account - 1] -= money;
        return true;
    }
}
#include <stdbool.h>

typedef struct {
    long* balance;
    int size;
} Bank;

Bank* bankCreate(long* balance, int size) {
    Bank* obj = (Bank*)malloc(sizeof(Bank));
    obj->balance = balance;
    obj->size = size;
    return obj;
}

bool bankTransfer(Bank* obj, int account1, int account2, long money) {
    if (account1 <= 0 || account1 > obj->size || account2 <= 0 || account2 > obj->size) return false;
    if (obj->balance[account1 - 1] < money) return false;
    obj->balance[account1 - 1] -= money;
    obj->balance[account2 - 1] += money;
    return true;
}

bool bankDeposit(Bank* obj, int account, long money) {
    if (account <= 0 || account > obj->size) return false;
    obj->balance[account - 1] += money;
    return true;
}

bool bankWithdraw(Bank* obj, int account, long money) {
    if (account <= 0 || account > obj->size || obj->balance[account - 1] < money) return false;
    obj->balance[account - 1] -= money;
    return true;
}

void bankFree(Bank* obj) {
    free(obj);
}
public class Bank {
    private long[] balance;
    
    public Bank(long[] balance) {
        this.balance = balance;
    }
    
    public bool Transfer(int account1, int account2, long money) {
        if (account1 <= 0 || account1 > balance.Length || account2 <= 0 || account2 > balance.Length) return false;
        if (balance[account1 - 1] < money) return false;
        balance[account1 - 1] -= money;
        balance[account2 - 1] += money;
        return true;
    }
    
    public bool Deposit(int account, long money) {
        if (account <= 0 || account > balance.Length) return false;
        balance[account - 1] += money;
        return true;
    }
    
    public bool Withdraw(int account, long money) {
        if (account <= 0 || account > balance.Length || balance[account - 1] < money) return false;
        balance[account - 1] -= money;
        return true;
    }
}

The Python solution offers a simple class structure, where methods perform checks and updates on the balance list with index adjustments for account numbers.

Complexity

Time Complexity: O(1), constant time operations per method.
Space Complexity: O(1), as there is no additional space usage apart from the initial storage.

Try this approach in the editor

Approach 2: HashMap for Account Balances

In this approach, we can use a hashmap (or dictionary for Python, Map for Java, etc.) where keys are account numbers and values are their respective balance amounts. It allows for a more dynamic setup, even though it's less efficient than direct array access due to its average constant time complexity for reads and writes.

class Bank:
    def __init__(self, balance):
        self.balance = {i + 1: balance[i] for i in range(len(balance))}
    
    def transfer(self, account1, account2, money):
        if account1 not in self.balance or account2 not in self.balance:
            return False
        if self.balance[account1] < money:
            return False
        self.balance[account1] -= money
        self.balance[account2] += money
        return True

    def deposit(self, account, money):
        if account not in self.balance:
            return False
        self.balance[account] += money
        return True

    def withdraw(self, account, money):
        if account not in self.balance or self.balance[account] < money:
            return False
        self.balance[account] -= money
        return True
import java.util.HashMap;
import java.util.Map;

class Bank {
    private Map<Integer, Long> balanceMap;
    
    public Bank(long[] balance) {
        balanceMap = new HashMap<>();
        for (int i = 0; i < balance.length; i++) {
            balanceMap.put(i + 1, balance[i]);
        }
    }
    
    public boolean transfer(int account1, int account2, long money) {
        if (!balanceMap.containsKey(account1) || !balanceMap.containsKey(account2)) return false;
        if (balanceMap.get(account1) < money) return false;
        balanceMap.put(account1, balanceMap.get(account1) - money);
        balanceMap.put(account2, balanceMap.get(account2) + money);
        return true;
    }
    
    public boolean deposit(int account, long money) {
        if (!balanceMap.containsKey(account)) return false;
        balanceMap.put(account, balanceMap.get(account) + money);
        return true;
    }
    
    public boolean withdraw(int account, long money) {
        if (!balanceMap.containsKey(account) || balanceMap.get(account) < money) return false;
        balanceMap.put(account, balanceMap.get(account) - money);
        return true;
    }
}

This Python implementation replaces the balance array with a dictionary to hold account numbers as keys and balance values. Although it slightly increases space usage, it offers flexibility should accounts need to be added dynamically.

Complexity

Time Complexity: O(1) on average due to hash table efficiency.
Space Complexity: O(n), storing all account balances in a dictionary.

Try this approach in the editor

Approach 3: Simulation

We can use an array balance to store the balance of each account. For each operation, we simply perform the required checks and updates according to the problem statement.

For the transfer operation, we need to check whether the account numbers are valid and whether the balance is sufficient. If the conditions are met, we perform the transfer.

For the deposit operation, we only need to check whether the account number is valid, and then perform the deposit.

For the withdraw operation, we need to check whether the account number is valid and whether the balance is sufficient. If the conditions are met, we perform the withdrawal.

Each operation has a time complexity of O(1), so the overall time complexity is O(q), where q is the number of operations. The space complexity is O(1).

class Bank {
    balance: number[];
    constructor(balance: number[]) {
        this.balance = balance;
    }

    transfer(account1: number, account2: number, money: number): boolean {
        if (
            account1 > this.balance.length ||
            account2 > this.balance.length ||
            money > this.balance[account1 - 1]
        )
            return false;
        this.balance[account1 - 1] -= money;
        this.balance[account2 - 1] += money;
        return true;
    }

    deposit(account: number, money: number): boolean {
        if (account > this.balance.length) return false;
        this.balance[account - 1] += money;
        return true;
    }

    withdraw(account: number, money: number): boolean {
        if (account > this.balance.length || money > this.balance[account - 1]) {
            return false;
        }
        this.balance[account - 1] -= money;
        return true;
    }
}

/**
 * Your Bank object will be instantiated and called as such:
 * var obj = new Bank(balance)
 * var param_1 = obj.transfer(account1,account2,money)
 * var param_2 = obj.deposit(account,money)
 * var param_3 = obj.withdraw(account,money)
 */
type Bank struct {
	balance []int64
	n       int
}

func Constructor(balance []int64) Bank {
	return Bank{balance, len(balance)}
}

func (this *Bank) Transfer(account1 int, account2 int, money int64) bool {
	if account1 > this.n || account2 > this.n || this.balance[account1-1] < money {
		return false
	}
	this.balance[account1-1] -= money
	this.balance[account2-1] += money
	return true
}

func (this *Bank) Deposit(account int, money int64) bool {
	if account > this.n {
		return false
	}
	this.balance[account-1] += money
	return true
}

func (this *Bank) Withdraw(account int, money int64) bool {
	if account > this.n || this.balance[account-1] < money {
		return false
	}
	this.balance[account-1] -= money
	return true
}

/**
 * Your Bank object will be instantiated and called as such:
 * obj := Constructor(balance);
 * param_1 := obj.Transfer(account1,account2,money);
 * param_2 := obj.Deposit(account,money);
 * param_3 := obj.Withdraw(account,money);
 */
struct Bank {
    balance: Vec<i64>,
}

/**
 * `&self` means the method takes an immutable reference.
 * If you need a mutable reference, change it to `&mut self` instead.
 */
impl Bank {
    fn new(balance: Vec<i64>) -> Self {
        Bank { balance }
    }

    fn transfer(&mut self, account1: i32, account2: i32, money: i64) -> bool {
        let (account1, account2, n) = (account1 as usize, account2 as usize, self.balance.len());
        if n < account1 || n < account2 {
            return false;
        }
        if self.balance[account1 - 1] < money {
            return false;
        }
        self.balance[account1 - 1] -= money;
        self.balance[account2 - 1] += money;
        true
    }

    fn deposit(&mut self, account: i32, money: i64) -> bool {
        let (account, n) = (account as usize, self.balance.len());
        if n < account {
            return false;
        }
        self.balance[account - 1] += money;
        true
    }

    fn withdraw(&mut self, account: i32, money: i64) -> bool {
        let (account, n) = (account as usize, self.balance.len());
        if n < account {
            return false;
        }
        if self.balance[account - 1] < money {
            return false;
        }
        self.balance[account - 1] -= money;
        true
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Direct Array Manipulation

Time Complexity: O(1), constant time operations per method.
Space Complexity: O(1), as there is no additional space usage apart from the initial storage.

HashMap for Account Balances

Time Complexity: O(1) on average due to hash table efficiency.
Space Complexity: O(n), storing all account balances in a dictionary.

Simulation–

Complexity analysis

ApproachTimeSpaceWhen to Use
Direct Array ManipulationO(1) per operationO(n)When account numbers map directly to indices and the total number of accounts is fixed
HashMap for Account BalancesO(1) average per operationO(n)When account identifiers may be sparse, dynamic, or not aligned with array indices

Frequently asked questions

Is Simple Bank System easy or hard?

The problem is rated Medium because it focuses on system design and edge-case handling rather than complex algorithms. The challenge comes from validating accounts, ensuring correct balance updates, and implementing all operations cleanly with constant-time performance.

Simple Bank System Python/Java solution

In Python or Java, the typical implementation stores balances in an array or list and exposes methods for transfer, deposit, and withdraw. Each method checks account validity, verifies sufficient funds when needed, and updates balances in constant time.

How to solve Simple Bank System in O(n)?

The overall design uses O(n) space to store balances, but each operation runs in O(1) time. Maintain an array or HashMap of balances, validate account indices or keys, check available funds for withdrawals or transfers, and update balances directly.

What is the best approach for Simple Bank System?

The direct array approach is usually the best solution. Account numbers map directly to array indices, allowing constant-time access for transfer, deposit, and withdrawal operations. Each operation performs simple checks and updates in O(1) time with O(n) space for storing balances.

Is Simple Bank System asked at Google/Amazon/Meta?

Problems involving banking operations and system simulations appear frequently in interviews at large tech companies. While this exact question may vary, the underlying concepts—designing operations with constant-time updates and validating state—are common in coding interviews.

What data structure is used in Simple Bank System?

The main data structures are arrays and hash tables. Arrays provide constant-time index access when account numbers are sequential, while HashMaps allow flexible mapping between account IDs and balances when identifiers are sparse or dynamic.

What is the time complexity of Simple Bank System?

Each operation—transfer, deposit, and withdraw—runs in O(1) time because it only accesses or updates a few stored balances. The system stores all balances in either an array or a HashMap, resulting in O(n) space complexity where n is the number of accounts.

Comments

Now write it yourselfClose this page and solve Simple Bank System in the editor, without looking.
Practise Simple Bank System