Banking System with Accepted Transfers, Part 4: Account Merging and Balance History
Problem statement
Implement a simplified banking system through four cumulative levels. The source exposes direct methods; this practice version serializes the same calls as one ordered String[][] queries batch and returns one string per query.
Timestamp and output rules
- Every query starts with an uppercase operation name followed by its arguments. All timestamps are unique integers from
1through10^9and arrive in strictly increasing order. - Serialize booleans as
trueorfalse, numbers in base 10, and conceptualnullresults as the empty string. - Before each external query at timestamp
t, expire every pending transfer whose acceptance window ended beforet. A transfer created atsremains acceptable throughs + 86400000and expires at the beginning of the next millisecond.
Level 1: Accounts, deposits, and payments
["CREATE_ACCOUNT", timestamp, accountId]implementscreateAccount. Create the account with balance zero and returntrue, or returnfalsewhen that active ID already exists.["DEPOSIT", timestamp, accountId, amount]implementsdeposit. Add the positive amount and return the resulting balance, or the empty string when the account does not exist.["PAY", timestamp, accountId, amount]implementspay. Subtract the positive amount and return the resulting balance. Return the empty string when the account is missing or has insufficient funds.
Level 2: Activity ranking
["TOP_ACTIVITY", timestamp, n]implementstopActivity. Rank active accounts by total transaction value descending and thenaccountIdascending.- Total transaction value is the sum of every successful processed amount affecting the account: deposits, payments, and both sides of an accepted transfer. Creating, rejecting, holding, expiring, refunding, or merely initiating a transfer adds no activity.
- Format entries as
accountId(total), join them with,, and return at mostnentries.
Level 3: Pending transfer acceptance
["TRANSFER", timestamp, sourceAccountId, targetAccountId, amount]implementstransfer. Hold the amount from the source until the target accepts or the transfer expires. Return the next global IDtransferK. Return the empty string, without consuming an ID, when the IDs are equal, either account is missing, or funds are insufficient.["ACCEPT_TRANSFER", timestamp, accountId, transferId]implementsacceptTransfer. Returntrueonly when the transfer is still pending andaccountIdis its current target; credit the target and add the amount to both accounts' transaction totals. Returnfalsefor a missing, accepted, canceled, expired, or wrong-target transfer.- An expired or canceled transfer refunds its held amount to its current source and never changes either transaction total.
Level 4: Account merging and historical balance
["MERGE_ACCOUNTS", timestamp, accountId1, accountId2]implementsmergeAccounts. Returnfalsewhen the IDs are equal or either active account is missing; otherwise merge Account 2 into Account 1 and returntrue.- Cancel every pending transfer whose source is Account 2 and refund its hold. Also cancel and refund every pending transfer from Account 1 to Account 2. Redirect every other pending transfer targeting Account 2 so that it targets Account 1.
- After those cancellations, add Account 2's balance and transaction total to Account 1. Account 1 keeps its ID; Account 2 is removed.
["GET_BALANCE", timestamp, accountId, timeAt]implementsgetBalance. Return that ID's balance immediately after all activity attimeAt, or after the latest earlier activity when nothing occurred exactly then. Return the empty string if that account generation did not exist attimeAt.- Before the merge, each ID keeps its own history. At the merge timestamp, Account 1 records the final combined balance and Account 2 stops existing. Account 2 remains queryable only for times before the merge.
Function
bankingAcceptedTransfersLevel4(queries: String[][]) → String[]Examples
Example 1
queries = [["CREATE_ACCOUNT","1","account1"],["CREATE_ACCOUNT","2","account1"],["CREATE_ACCOUNT","3","account2"],["DEPOSIT","4","non-existing","2700"],["DEPOSIT","5","account1","2700"],["PAY","6","non-existing","2700"],["PAY","7","account1","2701"],["PAY","8","account1","200"]]return = ["true","false","true","","2700","","","2500"]The duplicate account creation fails. Missing-account operations and an overdraw return empty strings. The final payment succeeds and leaves account1 with 2500.
Example 2
queries = [["CREATE_ACCOUNT","1","account1"],["CREATE_ACCOUNT","2","account2"],["CREATE_ACCOUNT","3","account3"],["DEPOSIT","4","account1","2000"],["DEPOSIT","5","account2","3000"],["DEPOSIT","6","account3","4000"],["TOP_ACTIVITY","7","3"],["PAY","8","account1","1500"],["PAY","9","account2","250"],["DEPOSIT","10","account3","250"],["TOP_ACTIVITY","11","3"]]return = ["true","true","true","2000","3000","4000","account3(4000), account2(3000), account1(2000)","500","2750","4250","account3(4250), account1(3500), account2(3250)"]The first ranking follows the three deposits. Payments count toward total activity even though they reduce balances, so the second ranking uses totals 4250, 3500, and 3250.
Example 3
queries = [["CREATE_ACCOUNT","1","account1"],["CREATE_ACCOUNT","2","account2"],["DEPOSIT","3","account1","2000"],["DEPOSIT","4","account2","3000"],["TRANSFER","5","account1","account2","5000"],["TRANSFER","16","account1","account2","1000"],["ACCEPT_TRANSFER","20","account1","transfer1"],["ACCEPT_TRANSFER","21","non-existing","transfer1"],["ACCEPT_TRANSFER","22","account1","transfer2"],["ACCEPT_TRANSFER","25","account2","transfer1"],["ACCEPT_TRANSFER","30","account2","transfer1"],["TRANSFER","40","account1","account2","1000"],["ACCEPT_TRANSFER","86400045","account2","transfer2"],["TRANSFER","86400050","account1","account1","1000"]]return = ["true","true","2000","3000","","transfer1","false","false","false","true","false","transfer2","false",""]The first transfer fails for insufficient funds. Only account2 can accept transfer1, and it can be accepted only once. transfer2 expires before timestamp 86400045, so its held funds are refunded and acceptance fails.
Example 4
queries = [["CREATE_ACCOUNT","1","a"],["CREATE_ACCOUNT","2","b"],["DEPOSIT","3","a","100"],["DEPOSIT","4","b","50"],["TRANSFER","5","b","a","20"],["MERGE_ACCOUNTS","6","a","b"],["GET_BALANCE","7","b","4"],["GET_BALANCE","8","b","5"],["GET_BALANCE","9","b","6"],["GET_BALANCE","10","a","6"],["TOP_ACTIVITY","11","2"]]return = ["true","true","100","50","transfer1","true","50","30","","150","a(150)"]The pending transfer would become internal after the merge, so it is canceled and its held 20 is refunded before the balances combine. Account b keeps its historical balances before timestamp 6 but is closed at the merge timestamp.
Constraints
1 <= queries.length <= 1000.- Every timestamp is a unique integer from
1through10^9, and queries are supplied in strictly increasing timestamp order. - Every query row is well formed and uses an operation available in Levels 1 through 4.
- Amounts and
nare positive base-10 integers. Every balance, transaction total, and pending-transfer due time fits in a signed 64-bit integer. - For
GET_BALANCE,0 <= timeAt <= timestamp. - Account identifiers are non-empty strings that do not contain commas or parentheses.
Source note: The four screenshots appear in the source carousel order: Level 4, Level 1, Level 2, and Level 3.