Design a bank system with scheduling and rankings
Company: Meta
Role: Software Engineer
Category: System Design
Difficulty: hard
Interview Round: Technical Screen
Design an in-memory bank system with the following APIs and guarantees:
1) createAccount(accountId, initialBalance=
0) -> void: Create a new account.
2) deposit(accountId, amount) -> bool: Increase balance; return false if accountId does not exist or amount <= 0.
3) withdraw(accountId, amount) -> bool: Transfer out funds; reject if insufficient balance or invalid input. Maintain each account’s cumulativeTransferredOut.
4) getTopSpenders(n) -> List<accountId>: Return the n accounts with the highest cumulativeTransferredOut. Break ties by smaller accountId. Results must reflect all successful withdraws and executed scheduled payments at the time of the call.
5) schedulePayment(accountId, amount, timestamp, delay) -> paymentId: Schedule a withdraw to execute at executeAt = timestamp + delay (timestamps are integers; delay >=
0). The payment counts toward cumulativeTransferredOut only upon successful execution.
6) cancel(paymentId) -> bool: Cancel a not-yet-executed payment.
7) process(nowTimestamp) -> string: Execute all due scheduled payments with executeAt <= nowTimestamp in ascending executeAt order; when executeAt ties, order by increasing paymentId. For each successfully executed payment, update balances and cumulativeTransferredOut. Return a single string that concatenates executed accounts’ IDs in that exact order, separated by commas (return an empty string if none executed).
Edge cases and rules:
- Amounts are positive integers; balances cannot go negative; failed executions (e.g., insufficient funds) do not affect cumulativeTransferredOut and are not included in the process() return string.
- Repeated operations may interleave arbitrarily. Assume single-threaded execution unless you choose to discuss concurrency controls.
- Complexity targets: O(
1) average-time for create/deposit/withdraw lookups and updates; O(log M) for scheduling/canceling/executing due payments using an appropriate priority structure where M is the number of pending payments; getTopSpenders(n) should be efficient for variable n queries (propose and justify a data structure choice and its trade-offs).
- Specify data structures, method signatures, and invariants. Describe how you would test correctness, handle idempotency (e.g., duplicate payment scheduling), and recover from partial failures (optional).
Quick Answer: This question evaluates system design and algorithmic skills for building an in-memory banking ledger, focusing on data modeling for accounts, scheduled timed withdrawals, maintenance of cumulative transfer rankings, and correctness under edge cases such as insufficient funds and payment cancellation.