FastPrepCredit Accounts with Scheduled Transfers

Credit Accounts with Scheduled Transfers

Airbnb logoAirbnb● HardFULLTIMEOA
Learn

Problem statement

Maintain credit accounts through a timestamped sequence of operations. Support account creation, credit additions, immediate transfers, balance ranking, scheduled transfers, cancellation, account merging and historical balance queries.

Operation ordering

Process queries in order. Each row contains an operation name, its timestamp and the arguments below. Before every external operation at timestamp t, process all pending transfers whose due time is at most t, ordered by due time and then scheduling order. Record a scheduled transfer's balance changes at its due time, even when the next external operation occurs later.

Return one string per external query. Use true or false for booleans, base-10 strings for numbers and an empty string for an unsuccessful numeric or identifier result.

Accounts and immediate transfers

  • ["CREATE_ACCOUNT", t, id]: create an account with balance zero and return true. Return false if that identifier has ever been created, including an identifier removed by a merge.
  • ["ADD_CREDIT", t, id, amount]: add positive credits to an active account and return its new balance. Return the empty string if the account is inactive or absent.
  • ["TRANSFER", t, source, target, amount]: transfer positive credits between distinct active accounts. Return the source balance after success. Return the empty string if either account is absent or inactive, the identifiers are equal or funds are insufficient.
  • ["TOP_K", t, k]: rank active accounts by current credit balance descending, breaking ties by identifier ascending. Return at most k entries formatted id(balance), joined by commas without spaces. Return the empty string if no active accounts exist.

Scheduled transfers

  • ["SCHEDULE_TRANSFER", t, source, target, amount, delay]: if the endpoints are distinct active accounts, schedule a transfer for t + delay and return the next global identifier transferK, starting with transfer1. An invalid request returns the empty string and consumes no identifier.
  • Scheduling does not reserve or move credits. When the transfer becomes due, execute it only if both endpoints remain active and the source has sufficient credits. Otherwise skip it permanently. A processed transfer is no longer pending whether it succeeds or fails.
  • ["CANCEL_TRANSFER", t, source, transferId]: return true and cancel the transfer only when it is pending and belongs to that active source account. Return false otherwise. Due transfers are processed before this cancellation, including transfers due exactly at t.

Merge and balance history

  • ["MERGE_ACCOUNTS", t, survivor, absorbed]: first process due transfers as usual. Return false if the identifiers are equal or either account is not active. Otherwise add the absorbed balance to the survivor, deactivate the absorbed account, cancel every remaining pending transfer having the absorbed account as either endpoint and return true. Pending transfers do not reserve funds, so cancellation does not refund credits.
  • ["GET_BALANCE", t, id, timeAt]: return that identifier's balance immediately after all activity at timeAt, or after its latest earlier activity if nothing occurred exactly then. Return the empty string if the account had not been created or was already deactivated at that historical time. A deactivated identifier remains queryable for its own pre-merge history.
  • The survivor keeps its own pre-merge history. Its combined balance starts at the merge timestamp. The absorbed identifier stops existing at the merge timestamp.

For this exercise, assume timestamps are strictly increasing, identifiers are never reused, transfers use positive integer credits without fees, failed scheduled transfers are not retried, and historical balances follow the identifier-specific rules above.

Function

processCreditAccounts(queries: String[][]) → String[]

Examples

Example 1

queries = [["CREATE_ACCOUNT","1","a"],["CREATE_ACCOUNT","2","b"],["ADD_CREDIT","3","a","100"],["ADD_CREDIT","4","b","30"],["TRANSFER","5","a","b","40"],["TOP_K","6","2"]]return = ["true","true","100","30","60","b(70),a(60)"]

The immediate transfer leaves a with 60 and b with 70. Ranking uses the current balances.

Example 2

queries = [["CREATE_ACCOUNT","1","a"],["CREATE_ACCOUNT","2","b"],["CREATE_ACCOUNT","3","c"],["ADD_CREDIT","4","b","100"],["SCHEDULE_TRANSFER","5","b","c","30","5"],["SCHEDULE_TRANSFER","6","b","c","20","10"],["MERGE_ACCOUNTS","10","a","b"],["GET_BALANCE","11","c","10"],["GET_BALANCE","12","b","9"],["GET_BALANCE","13","b","10"],["GET_BALANCE","16","a","16"]]return = ["true","true","true","100","transfer1","transfer2","true","30","100","","70"]

The first scheduled transfer executes at timestamp 10 before the merge, leaving b with 70 and c with 30. The merge moves 70 into a and cancels the second transfer. Account b remains queryable at timestamp 9 but no longer exists at timestamp 10.

Example 3

queries = [["CREATE_ACCOUNT","1","a"],["CREATE_ACCOUNT","2","b"],["ADD_CREDIT","3","a","50"],["SCHEDULE_TRANSFER","4","a","b","40","6"],["SCHEDULE_TRANSFER","5","a","b","30","5"],["CANCEL_TRANSFER","10","a","transfer1"],["TOP_K","11","2"],["GET_BALANCE","12","a","10"]]return = ["true","true","50","transfer1","transfer2","false","b(40),a(10)","10"]

Both scheduled transfers are due at timestamp 10. The earlier scheduled transfer succeeds first; the second lacks funds and is skipped. Cancellation occurs afterward and returns false.

Constraints

  • 1 <= queries.length <= 500.
  • External timestamps are strictly increasing integers from 0 through 10^9.
  • Every query has a valid operation shape. Amounts and delays are positive integers at most 10^9.
  • Account identifiers contain only ASCII letters, digits and underscores, with length from 1 through 32.
  • Every balance and derived due time fits in a signed 64-bit integer.
  • For TOP_K, 1 <= k <= 500. For GET_BALANCE, 0 <= timeAt <= t.

More Airbnb problems

See Airbnb hiring insights
public String[] processCreditAccounts(String[][] queries) {
    // Write your code here.
}
queries[["CREATE_ACCOUNT","1","a"],["CREATE_ACCOUNT","2","b"],["ADD_CREDIT","3","a","100"],["ADD_CREDIT","4","b","30"],["TRANSFER","5","a","b","40"],["TOP_K","6","2"]]
expected["true", "true", "100", "30", "60", "b(70),a(60)"]
Checking account…