Implement a Time-Aware Banking System
AirbnbSoftware Engineer · Online AssessmentLast updated
Design and implement a stateful, time-aware in-memory banking ledger that handles atomic transfers, deferred/scheduled executions, account mergers, historical balance queries, and activity rankings.
Problem Statement
Implement an in-memory banking system that processes operations sequentially under a monotonically increasing timestamp. The system must process pending scheduled transfers up to the current timestamp before executing any new operation.
Implement the BankSystem class with the following methods:
create_account(timestamp: int, account_id: str) -> bool: Creates an account with a balance of0. ReturnsTrueif created successfully, orFalseifaccount_idalready exists.deposit(timestamp: int, account_id: str, amount: int) -> int | None: Addsamounttoaccount_id. Returns the new balance, orNoneif the account does not exist.transfer(timestamp: int, from_id: str, to_id: str, amount: int) -> bool: Immediately transfersamountfromfrom_idtoto_id. Both accounts must exist,from_id != to_id, andfrom_idmust have balance>= amount. ReturnsTrueon success,Falseotherwise.schedule_transfer(timestamp: int, scheduled_time: int, transfer_id: str, from_id: str, to_id: str, amount: int) -> bool: Schedules a transfer atscheduled_time. ReturnsFalseifscheduled_time bool: Cancels a pending scheduled transfer. ReturnsTrueif successfully cancelled, orFalseiftransfer_iddoes not exist or has already executed.merge_accounts(timestamp: int, target_id: str, source_id: str) -> bool: Mergessource_idintotarget_id. Moves the remaining balance ofsource_idtotarget_id, rebinds all pending scheduled transfers involvingsource_idtotarget_id, and deactivatessource_id. Both accounts must exist andtarget_id != source_id. ReturnsTrueon success,Falseotherwise.get_balance(timestamp: int, account_id: str, as_of_time: int) -> int | None: Returns the account balance exactly atas_of_time(as_of_time list[str]: Returns the topnaccounts by total outbound transfer volume (including direct and scheduled transfers, excluding deposits and balance merges). Tie-break accounts alphabetically.
Execution Rules
- Across all API calls,
timestampis non-decreasing. - Before any operation at
timestampexecutes, all scheduled transfers wherescheduled_time <= timestampmust execute in chronological order. Break ties bytransfer_idlexicographically. - If an account has insufficient funds at the scheduled execution time, the transfer fails silently and is discarded.
Example
bank = BankSystem()
bank.create_account(1, "A") # True
bank.create_account(1, "B") # True
bank.deposit(2, "A", 100) # 100
bank.schedule_transfer(3, 10, "t1", "A", "B", 40) # True
bank.get_balance(5, "A", 4) # 100 (balance at t=4)
bank.get_balance(11, "A", 10) # 60 (t1 executed at t=10)
bank.get_top_spenders(12, 1) # ["A"]
Constraints
- All
timestampandscheduled_timeare integers where1 0. - At most
20,000total method calls.
Hints
Hint 1
Maintain a min-heap of pending scheduled transfers ordered by `(scheduled_time, transfer_id)` and process due items before every method call.
Hint 2
Record every balance-mutating event with its timestamp per account so historical balances can be retrieved via binary search (bisection).
Hint 3
When merging accounts, remember to update pending transfers in the heap or use an indirection mapping (pointer/alias) so rebinding does not require rebuilding the heap.
Follow-up questions
- How would you optimize `merge_accounts` if accounts have thousands of pending transfers?
- If timestamps could arrive out of order from distributed clients, how would you redesign the settlement boundary and conflict resolution?
- How would you support recurring scheduled payments (e.g., cron or interval-based) without creating an unbounded number of future records?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.