2043. Simple Bank System
Problem Description
This problem simulates the operations of a bank with n
accounts through a class called Bank
. Each account in the bank is numbered from 1 to n
, and the initial balance for each account is given in a 0-indexed array; this means that the balance of the i-th account in the array corresponds to account number i + 1 in our bank. The Bank
class needs to support three types of transactions: transfers between two accounts, deposits into an account, and withdrawals from an account. A transaction is considered valid if the account numbers are within the valid range (1 to n
) and for transfers and withdrawals, there is enough money in the account to cover the transaction. Implementing the required functionality in the Bank
class involves creating methods that successfully handle these transactions while maintaining accurate account balances and ensuring all business rules are respected.
Intuition
When designing the Bank
class and its methods, we should first consider the constraints around account numbers and balances. To handle transactions, we need to check that the requested operation is valid: the account number(s) must be within the valid range and there must be sufficient funds to complete a withdrawal or transfer.
We start with the constructor __init__
, which initializes the Bank
with a list of account balances and the total number of accounts. This sets up our initial state.
For the transfer
method, we check the validity of the account numbers and the availability of funds in the source account. If these conditions are met, we subtract the transferred money from account1
and add it to account2
. If the conditions are not met, we return False
.
The deposit
method is slightly simpler, as it only requires a check to ensure the account exists (the account number is within range). If it does, we add the money to the account's balance.
The withdraw
method involves checking both the account number validity and the availability of funds, much like the transfer
method. If the checks pass, we subtract the money from the account.
Each of these methods returns a boolean indicating whether the operation was successful (True
) or not (False
).
By carefully following the rules stated in the problem description and using basic conditional statements to enforce the rules, we arrive at a straightforward solution that satisfies all the requirements of the Bank
class.
Solution Approach
The solution is structured around the Bank
class with three key methods: transfer
, deposit
, and withdraw
.
-
The
__init__
constructor simply assigns the provided balance list and calculates the number of accounts using thelen
function which is stored inself.n
. -
For the
transfer
method:- It first checks if both the source (
account1
) and destination (account2
) account numbers are within the valid range by comparing them withself.n
. It also checks if the source account has enough balance to transfer by comparingmoney
with the balance ofaccount1
. - If any condition fails, it returns
False
. - If the conditions are met, the method subtracts the amount of
money
from the balance ofaccount1
and adds that amount to the balance ofaccount2
. - It finally returns
True
indicating a successful transaction.
- It first checks if both the source (
-
For the
deposit
method:- It verifies if the account number is valid.
- If the account is invalid, it returns
False
. - If valid, it adds the
money
to the balance of the specified account. - It then returns
True
to signify success.
-
The
withdraw
method:- Checks if the account number is within the valid range and if the account has a balance greater than or equal to the withdrawal
money
. - Should the account not exist or have insufficient funds, the method returns
False
. - Otherwise, it subtracts the withdrawal
money
from the account's balance and returnsTrue
.
- Checks if the account number is within the valid range and if the account has a balance greater than or equal to the withdrawal
The design employs basic array indexing to represent individual account balances. This simple data structure is effective in providing efficient direct access to specific elements, which is essential for operations like transfer
, deposit
, and withdraw
that require looking up and modifying values based on account numbers. Conditionals (if-else statements) are used throughout to enforce business rules and validate transactions.
Overall, the solution follows a pragmatic approach, applying core programming constructs like lists, condition checking, arithmetic operations, and boolean return values to fulfill the transaction requirements of a banking system.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Consider a scenario where we have a Bank
with 3 accounts. The initial balances for these accounts are [10, 100, 20]
, which correspond to accounts 1, 2, and 3 respectively. Let's walk through a series of transactions to demonstrate the solution approach.
-
Initialization:
- We create a
Bank
object using the initial balances. - The
__init__
method sets up our internal state with these balances and establishes that we have 3 accounts.
- We create a
-
Deposit Attempt:
- We call the
deposit
method for account number 2 with an amount of50
. - The method checks if account number 2 is valid (which is true, as it's within the range of 1 to 3).
- It adds 50 to account number 2's balance, resulting in the new balances being
[10, 150, 20]
. - The method returns
True
since the transaction was successful.
- We call the
-
Withdrawal Attempt:
- Next, we attempt to withdraw
30
from account number 3. - The
withdraw
method checks if account 3 has at least30
. It does, so the money is subtracted. - The balance is updated to
[10, 150, -10]
, and the method returnsTrue
. - Note: This outcome reveals an oversight in the provided approach, as it allows the balance to go negative. A real implementation should check and ensure the withdrawal does not result in a negative balance, so the transaction should instead return
False
.
- Next, we attempt to withdraw
-
Transfer Attempt:
- We now want to transfer
100
from account 1 to account 3. We call thetransfer
method withaccount1 = 1
,account2 = 3
, andmoney = 100
. - The
transfer
method first checks if account 1 exists and has at least100
to transfer. It doesn't, as the balance is currently10
. - Since there are insufficient funds, the method returns
False
, and no transfer occurs.
- We now want to transfer
Through this example, the essential process of depositing, withdrawing, and transferring money between accounts is illustrated using array indexing, condition statements, and boolean values to handle the business logic of these transactions systematically. However, modifications might be necessary to prevent negative account balances as noted in step 3.
Solution Implementation
1# Define the Bank class with appropriate methods for banking operations
2class Bank:
3 def __init__(self, balance: List[int]):
4 self.balance = balance # Initialize an account balance list
5 self.num_accounts = len(balance) # Store the number of accounts based on the length of the balance list
6
7 # Transfer money from one account to another if valid and possible
8 def transfer(self, account1: int, account2: int, money: int) -> bool:
9 # Check for valid account numbers and sufficient funds before transfer
10 if account1 > self.num_accounts or account2 > self.num_accounts or self.balance[account1 - 1] < money:
11 return False # conditions not met, return False
12
13 # Perform the transfer
14 self.balance[account1 - 1] -= money # Deduct money from the source account
15 self.balance[account2 - 1] += money # Add money to the destination account
16 return True # return True on successful transfer
17
18 # Deposit money into a given account if the account is valid
19 def deposit(self, account: int, money: int) -> bool:
20 # Check if the account number is valid
21 if account > self.num_accounts:
22 return False # Invalid account, return False
23
24 # Perform the deposit
25 self.balance[account - 1] += money # Add the money to the account balance
26 return True # return True on successful deposit
27
28 # Withdraw money from a given account if the account is valid and has sufficient funds
29 def withdraw(self, account: int, money: int) -> bool:
30 # Check for valid account number and if the account has sufficient funds
31 if account > self.num_accounts or self.balance[account - 1] < money:
32 return False # conditions not met, return False
33
34 # Perform the withdrawal
35 self.balance[account - 1] -= money # Deduct the money from the account balance
36 return True # return True on successful withdrawal
37
38
39# Example of instantiation and method calls:
40# obj = Bank(balance)
41# success_transfer = obj.transfer(account1, account2, money)
42# success_deposit = obj.deposit(account, money)
43# success_withdraw = obj.withdraw(account, money)
44
1class Bank {
2 private long[] balances; // An array to store the balance of each account.
3 private int accountCount; // The total number of accounts in the bank.
4
5 // Constructor to initialize the bank with a given array of balances.
6 public Bank(long[] balances) {
7 this.balances = balances;
8 this.accountCount = balances.length;
9 }
10
11 // Method to transfer money from one account to another.
12 public boolean transfer(int fromAccount, int toAccount, long amount) {
13 // Check if either account number is invalid or if the fromAccount has insufficient funds.
14 if (fromAccount > accountCount || toAccount > accountCount || balances[fromAccount - 1] < amount) {
15 return false; // Return false to indicate the transfer failed.
16 }
17 // Deduct the amount from the sender's account.
18 balances[fromAccount - 1] -= amount;
19 // Add the amount to the receiver's account.
20 balances[toAccount - 1] += amount;
21 return true; // Return true to indicate the transfer was successful.
22 }
23
24 // Method to deposit money into an account.
25 public boolean deposit(int account, long amount) {
26 // Check if the account number is invalid.
27 if (account > accountCount) {
28 return false; // Return false to indicate the deposit failed.
29 }
30 // Add the amount to the account's balance.
31 balances[account - 1] += amount;
32 return true; // Return true to indicate the deposit was successful.
33 }
34
35 // Method to withdraw money from an account.
36 public boolean withdraw(int account, long amount) {
37 // Check if the account number is invalid or if the account has insufficient funds.
38 if (account > accountCount || balances[account - 1] < amount) {
39 return false; // Return false to indicate the withdrawal failed.
40 }
41 // Deduct the amount from the account's balance.
42 balances[account - 1] -= amount;
43 return true; // Return true to indicate the withdrawal was successful.
44 }
45}
46
1#include <vector>
2
3class Bank {
4public:
5 // Use underscore naming for private member variables to distinguish from method parameters
6 std::vector<long long> _balances;
7 int _numAccounts; // Variable to store the number of accounts
8
9 // Constructor to initialize the Bank object with a list of balances
10 Bank(std::vector<long long>& balances) {
11 _balances = balances;
12 _numAccounts = balances.size();
13 }
14
15 // Transfer method - moves 'money' from 'account1' to 'account2'
16 bool transfer(int account1, int account2, long long money) {
17 // Check if either of the account numbers are invalid or if the balance is insufficient
18 if (account1 > _numAccounts || account2 > _numAccounts || _balances[account1 - 1] < money) {
19 return false;
20 }
21 // Perform the transfer by adjusting the balances of both accounts
22 _balances[account1 - 1] -= money;
23 _balances[account2 - 1] += money;
24 return true;
25 }
26
27 // Deposit method - adds 'money' to 'account'
28 bool deposit(int account, long long money) {
29 // Check if the account number is invalid
30 if (account > _numAccounts) {
31 return false;
32 }
33 // Increase the balance of the account by 'money'
34 _balances[account - 1] += money;
35 return true;
36 }
37
38 // Withdraw method - deducts 'money' from 'account'
39 bool withdraw(int account, long long money) {
40 // Check if the account number is invalid or if the balance is insufficient
41 if (account > _numAccounts || _balances[account - 1] < money) {
42 return false;
43 }
44 // Decrease the balance of the account by 'money'
45 _balances[account - 1] -= money;
46 return true;
47 }
48};
49
1// The balance for each account.
2let bankBalance: number[];
3
4/**
5 * Initializes the bank balance.
6 *
7 * @param {number[]} balance - The initial amount of money in each account.
8 */
9function initializeBankBalance(balance: number[]): void {
10 bankBalance = balance;
11}
12
13/**
14 * Transfers money from one account to another.
15 *
16 * @param {number} accountFrom - The account number to transfer money from.
17 * @param {number} accountTo - The account number to transfer money to.
18 * @param {number} amount - The amount of money to transfer.
19 * @returns {boolean} True if the transfer was successful, false otherwise.
20 */
21function transfer(accountFrom: number, accountTo: number, amount: number): boolean {
22 // Check for valid account numbers and sufficient balance in the source account.
23 if (
24 accountFrom > bankBalance.length ||
25 accountTo > bankBalance.length ||
26 amount > bankBalance[accountFrom - 1]
27 )
28 return false;
29
30 // Perform the transfer.
31 bankBalance[accountFrom - 1] -= amount;
32 bankBalance[accountTo - 1] += amount;
33 return true;
34}
35
36/**
37 * Deposits money into an account.
38 *
39 * @param {number} account - The account number to deposit money into.
40 * @param {number} amount - The amount of money to deposit.
41 * @returns {boolean} True if the deposit was successful, false otherwise.
42 */
43function deposit(account: number, amount: number): boolean {
44 // Check for a valid account number.
45 if (account > bankBalance.length) return false;
46
47 // Perform the deposit.
48 bankBalance[account - 1] += amount;
49 return true;
50}
51
52/**
53 * Withdraws money from an account.
54 *
55 * @param {number} account - The account number to withdraw money from.
56 * @param {number} amount - The amount of money to withdraw.
57 * @returns {boolean} True if the withdrawal was successful, false otherwise.
58 */
59function withdraw(account: number, amount: number): boolean {
60 // Check for valid account numbers and sufficient balance.
61 if (account > bankBalance.length || amount > bankBalance[account - 1]) {
62 return false;
63 }
64
65 // Perform the withdrawal.
66 bankBalance[account - 1] -= amount;
67 return true;
68}
69
70// Example usage:
71// initializeBankBalance([100, 200, 300]);
72// const transferSuccess = transfer(1, 2, 50);
73// const depositSuccess = deposit(3, 75);
74// const withdrawalSuccess = withdraw(2, 25);
75
Time and Space Complexity
Time Complexity
-
__init__()
: The time complexity isO(1)
because only a reference to the list is created (assuming that the list is passed by reference and not copied). -
transfer(account1, account2, money)
: The time complexity isO(1)
because it performs a constant number of operations: checking whether the accounts are valid, whether the balance is sufficient, and updating the balances. -
deposit(account, money)
: The time complexity isO(1)
as it involves a simple validation of the account existence and an addition operation on the balance. -
withdraw(account, money)
: The time complexity isO(1)
since it includes the checking of whether the account exists and whether the balance is enough, followed by the subtraction from the balance.
Space Complexity
-
__init__()
: The space complexity isO(n)
because it stores a list of balances forn
accounts, wheren
is the length of the initial list. Here,n
represents the number of accounts. -
transfer(account1, account2, money)
: The space complexity isO(1)
as it does not use any additional space that scales with the input size. -
deposit(account, money)
: The space complexity isO(1)
given that no extra space proportional to the size of input data is used besides what is already stored in the Bank class. -
withdraw(account, money)
: The space complexity is alsoO(1)
for the same reason as deposit and transfer; it does not require additional space depending on the input.
Learn more about how to find time and space complexity quickly using problem constraints.
Problem: Given a list of tasks and a list of requirements, compute a sequence of tasks that can be performed, such that we complete every task once while satisfying all the requirements.
Which of the following method should we use to solve this problem?
Recommended Readings
LeetCode Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way we
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https algomonster s3 us east 2 amazonaws com recursion jpg You first
Runtime Overview When learning about algorithms and data structures you'll frequently encounter the term time complexity This concept is fundamental in computer science and offers insights into how long an algorithm takes to complete given a certain input size What is Time Complexity Time complexity represents the amount of time
Want a Structured Path to Master System Design Too? Don’t Miss This!