Design an in-memory banking service supporting timestamped operations and edge-case semantics. Implement:
(
-
create_account(id, t): Create a new account at timestamp t. Return false if id currently exists and has not been merged since its last existence. After an account id is merged away, it may be created again at a later timestamp with balance initialized to 0, without erasing pre-merge historical activities.
(
-
deposit(id, amount, t) and pay(id, amount, t): Update balance at timestamp t; amounts are non-negative integers; reject pay if insufficient funds.
(
-
transfer(src, dst, amount, t) to initiate a pending transfer that immediately debits src’s available balance; accept_transfer(dst, transfer_id, t
-
to finalize the transfer into dst at timestamp t2. Activity counting rule: only finalized transfers (at t
-
contribute to activity; initiating a transfer does not.
(
-
top_activity(t, k): At timestamp t, return the k account ids with the largest 'activity' at t, where an account’s activity at t is the sum of absolute amounts of all operations occurring exactly at timestamp t for that account (e.g., deposit 200 and pay 100 at the same t yields activity
300). If an account id was merged before t, it must not appear for t or later; its historical activity prior to the merge remains queryable at earlier timestamps.
(
-
merge_accounts(dst, src, t): Merge src into dst at timestamp t. After merge, queries for src at any timestamp ≥ t (balance, activity, etc.) return None; dst’s balance/history continue. The id src may be re-created later via create_account(src, t'), in which case its balance resets to 0 starting at t', without altering pre-merge history.
(
-
get_balance(id, t): Return the account’s balance as of timestamp t. Specify:
(a) data structures to support these semantics efficiently;
(b) exact return values for invalid operations and the edge cases noted above;
(c) time/space complexity of each operation;
(d) a unit-testing plan that covers the tricky merge and activity rules.