Implement a Banking System
Company: Anthropic
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Quick Answer: This question evaluates skills in designing and implementing a stateful in-memory banking system, covering account modeling, transfer lifecycle and expiration handling, balance management, and tracking aggregate outgoing amounts.
Constraints
- 1 <= len(operations) <= 2000
- 0 <= timestamp <= 10^12, and timestamps are non-decreasing
- Account ids are non-empty strings
- 0 <= amount <= 10^9
- 0 <= n <= number of operations
- TRANSFER_EXPIRATION_MS = 86,400,000
- A transfer created at t expires before processing operations with timestamp > t + TRANSFER_EXPIRATION_MS
Examples
Input: ([('create_account', 1, 'alice'), ('create_account', 2, 'alice'), ('deposit', 3, 'bob', 50), ('create_account', 4, 'bob'), ('deposit', 5, 'alice', 100), ('deposit', 6, 'bob', 100), ('top_outgoing', 7, 3), ('top_outgoing', 8, 0)],)
Expected Output: [True, False, None, True, 100, 100, ['alice', 'bob'], []]
Explanation: Duplicate account creation fails, depositing to a missing account returns None, and accounts with equal outgoing totals are sorted lexicographically. Requesting the top 0 accounts returns an empty list.
Input: ([('create_account', 1, 'A'), ('create_account', 2, 'B'), ('deposit', 3, 'A', 500), ('transfer', 4, 'A', 'B', 200), ('top_outgoing', 5, 2), ('accept_transfer', 6, 'A', 'transfer1'), ('accept_transfer', 7, 'B', 'transfer1'), ('top_outgoing', 8, 2), ('deposit', 9, 'B', 50), ('accept_transfer', 10, 'B', 'transfer1')],)
Expected Output: [True, True, 500, 'transfer1', ['A', 'B'], False, True, ['A', 'B'], 250, False]
Explanation: The pending transfer does not count as outgoing before acceptance. Accepting with the wrong target fails. After B accepts, B receives 200 and A's outgoing total becomes 200. Accepting the same transfer again fails.
Input: ([('create_account', 0, 'A'), ('create_account', 1, 'B'), ('deposit', 2, 'A', 1000), ('transfer', 10, 'A', 'B', 300), ('accept_transfer', 86400010, 'B', 'transfer1'), ('transfer', 86400011, 'B', 'A', 100), ('deposit', 172800012, 'B', 50), ('accept_transfer', 172800013, 'A', 'transfer2'), ('top_outgoing', 172800014, 2)],)
Expected Output: [True, True, 1000, 'transfer1', True, 'transfer2', 350, False, ['A', 'B']]
Explanation: transfer1 is accepted exactly at its expiration boundary, so it succeeds. transfer2 expires before the later deposit, so its withheld 100 is returned to B before depositing 50, producing balance 350. The expired transfer cannot be accepted and does not count as outgoing.
Input: ([('create_account', 1, 'A'), ('create_account', 2, 'C'), ('deposit', 3, 'A', 10), ('transfer', 4, 'A', 'C', 20), ('transfer', 5, 'A', 'A', 1), ('transfer', 6, 'A', 'X', 1), ('deposit', 7, 'A', 0), ('top_outgoing', 8, 5)],)
Expected Output: [True, True, 10, None, None, None, 10, ['A', 'C']]
Explanation: Transfers fail for insufficient funds, same source and target, and missing target account. Depositing 0 is allowed and leaves the balance unchanged.
Input: ([('create_account', 1, 'A'), ('create_account', 2, 'B'), ('create_account', 3, 'C'), ('deposit', 4, 'A', 1000), ('deposit', 5, 'B', 500), ('deposit', 6, 'C', 200), ('transfer', 7, 'A', 'B', 300), ('transfer', 8, 'B', 'A', 100), ('transfer', 9, 'C', 'B', 50), ('transfer', 10, 'B', 'C', 200), ('merge_accounts', 11, 'A', 'B'), ('deposit', 12, 'A', 0), ('accept_transfer', 13, 'A', 'transfer3'), ('accept_transfer', 14, 'C', 'transfer4'), ('top_outgoing', 15, 3), ('deposit', 16, 'C', 0), ('accept_transfer', 17, 'B', 'transfer1')],)
Expected Output: [True, True, True, 1000, 500, 200, 'transfer1', 'transfer2', 'transfer3', 'transfer4', True, 1300, True, True, ['A', 'C'], 350, False]
Explanation: When B merges into A, pending transfers A->B and B->A are canceled and their withheld amounts are returned. Pending transfer C->B is redirected to C->A, and pending transfer B->C is redirected to A->C. After accepting them, A has outgoing 200 and C has outgoing 50.
Input: ([('create_account', 1, 'A'), ('create_account', 2, 'B'), ('create_account', 3, 'C'), ('deposit', 4, 'B', 100), ('transfer', 5, 'B', 'C', 40), ('accept_transfer', 6, 'C', 'transfer1'), ('top_outgoing', 7, 3), ('merge_accounts', 8, 'A', 'B'), ('top_outgoing', 9, 3), ('deposit', 10, 'A', 10)],)
Expected Output: [True, True, True, 100, 'transfer1', True, ['B', 'A', 'C'], True, ['A', 'C'], 70]
Explanation: B's completed outgoing total of 40 is added to A during the merge. B's remaining balance 60 is also moved to A, so depositing 10 afterward returns 70.
Hints
- Use dictionaries to store account state and transfer state. For each account, track both available balance and completed outgoing total.
- Remember that pending transfers withhold money immediately, but they only affect outgoing totals when accepted. Expiration and merging both need to update pending transfers carefully.