FastPrepBanking System with Accepted Transfers, Part 4: Account Merging and Balance History

Banking System with Accepted Transfers, Part 4: Account Merging and Balance History

Airbnb logoAirbnb● HardFULLTIMEOA
Learn

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 1 through 10^9 and arrive in strictly increasing order.
  • Serialize booleans as true or false, numbers in base 10, and conceptual null results as the empty string.
  • Before each external query at timestamp t, expire every pending transfer whose acceptance window ended before t. A transfer created at s remains acceptable through s + 86400000 and expires at the beginning of the next millisecond.

Level 1: Accounts, deposits, and payments

  • ["CREATE_ACCOUNT", timestamp, accountId] implements createAccount. Create the account with balance zero and return true, or return false when that active ID already exists.
  • ["DEPOSIT", timestamp, accountId, amount] implements deposit. Add the positive amount and return the resulting balance, or the empty string when the account does not exist.
  • ["PAY", timestamp, accountId, amount] implements pay. 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] implements topActivity. Rank active accounts by total transaction value descending and then accountId ascending.
  • 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 most n entries.

Level 3: Pending transfer acceptance

  • ["TRANSFER", timestamp, sourceAccountId, targetAccountId, amount] implements transfer. Hold the amount from the source until the target accepts or the transfer expires. Return the next global ID transferK. 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] implements acceptTransfer. Return true only when the transfer is still pending and accountId is its current target; credit the target and add the amount to both accounts' transaction totals. Return false for 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] implements mergeAccounts. Return false when the IDs are equal or either active account is missing; otherwise merge Account 2 into Account 1 and return true.
  • 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] implements getBalance. Return that ID's balance immediately after all activity at timeAt, or after the latest earlier activity when nothing occurred exactly then. Return the empty string if that account generation did not exist at timeAt.
  • 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 1 through 10^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 n are 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.

More Airbnb problems

See Airbnb hiring insights
public String[] bankingAcceptedTransfersLevel4(String[][] queries) {
  // Process the queries in order and return one string per query.
  // write your code here
}
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"]]
expected["true", "false", "true", "", "2700", "", "", "2500"]
Checking account…