FastPrepProgressive Banking System with Cashback

Progressive Banking System with Cashback

Airbnb logoAirbnb● HardFULLTIMEOA
Learn

Problem statement

Implement a progressive banking system. All operations have a timestamp parameter — a stringified timestamp in milliseconds. All timestamps are unique, lie in the range from 1 to 10^9, and are supplied in strictly increasing order.

Before every operation at timestamp t, process every cashback whose due time is at most t. A cashback due exactly at t is credited before that operation.

Level 1

Initially, the banking system does not contain any accounts. Support account creation, deposits, and transfers between two different accounts:

  • createAccount(timestamp, accountId) creates a new account with the given identifier if it does not already exist. It returns true when the account is created and false when an active account with accountId already exists.
  • deposit(timestamp, accountId, amount) deposits the given amount into the specified account and returns its resulting balance. It returns null when the account does not exist.
  • transfer(timestamp, sourceAccountId, targetAccountId, amount) transfers the given amount from the source account to the target account and returns the resulting source balance. It returns null when either account is missing, the identifiers are equal, or the source has insufficient funds.

Level 2

topSpenders(timestamp, n) returns up to n active accounts with the highest total outgoing transactions. Outgoing transactions include successful transfers out and successful payments. Sort by outgoing total in descending order, then by accountId in ascending lexicographic order. Format every entry as accountId(totalOutgoing). If fewer than n accounts exist, return all of them. Cashback never counts as outgoing activity.

Level 3

  • pay(timestamp, accountId, amount) withdraws the amount when the account exists and has sufficient funds. A successful payment contributes to outgoing activity, returns the next global identifier paymentK, and schedules floor(amount * 2 / 100) cashback for timestamp + 86400000. A failed payment returns null and does not consume an identifier.
  • getPaymentStatus(timestamp, accountId, payment) returns IN_PROGRESS before that payment's cashback is processed and CASHBACK_RECEIVED afterward. It returns null when the account or payment does not exist, or when the payment belongs to a different current account lineage.

Level 4

  • mergeAccounts(timestamp, accountId1, accountId2) merges accountId2 into accountId1. It returns false if the identifiers are equal or either active account is missing; otherwise it returns true.
  • The survivor receives the absorbed balance and outgoing total. Pending cashback follows the survivor, old payments from the absorbed account become queryable through the survivor, and accountId2 is removed. A removed identifier may later be created as a new, independent account.
  • getBalance(timestamp, accountId, timeAt) returns the account balance immediately after all activity at timeAt, or after the latest earlier activity when nothing happened exactly then. It returns null if accountId is not active at the query timestamp or if that surviving account did not yet exist at timeAt.
  • After a merge, the survivor inherits the absorbed account's balance history. For a historical time when both lineages existed, the survivor's historical balance is their sum; internal transfers between the two lineages cancel naturally.

FastPrep Batch Interface

Implement processBankingQueries(queries). Each row contains an uppercase operation name followed by the arguments shown below. Return one string per query in the same order.

  • Use CREATE_ACCOUNT, DEPOSIT, TRANSFER, TOP_SPENDERS, PAY, GET_PAYMENT_STATUS, MERGE_ACCOUNTS, and GET_BALANCE.
  • Serialize booleans as true or false, numbers in base 10, and every conceptual null as the empty string.
  • Serialize TOP_SPENDERS by joining its formatted entries with commas and no spaces.

Function

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

Examples

Example 1

queries = [["CREATE_ACCOUNT","1","alice"],["CREATE_ACCOUNT","2","bob"],["DEPOSIT","3","alice","1000"],["TRANSFER","4","alice","bob","250"],["TOP_SPENDERS","5","2"]]return = ["true","true","1000","750","alice(250),bob(0)"]

The transfer leaves alice with 750 and records 250 of outgoing activity for alice. Bob has no outgoing activity, so alice ranks first.

Example 2

queries = [["CREATE_ACCOUNT","1","a"],["DEPOSIT","2","a","1000"],["PAY","3","a","200"],["GET_PAYMENT_STATUS","4","a","payment1"],["DEPOSIT","86400003","a","1"],["GET_PAYMENT_STATUS","86400004","a","payment1"],["GET_BALANCE","86400005","a","86400003"]]return = ["true","1000","payment1","IN_PROGRESS","805","CASHBACK_RECEIVED","805"]

Paying 200 leaves 800 and schedules floor(2% of 200) = 4 for timestamp 86400003. The cashback is credited before the deposit at that same timestamp, so the deposit returns 805.

Example 3

queries = [["CREATE_ACCOUNT","1","a"],["DEPOSIT","2","a","100"],["CREATE_ACCOUNT","3","b"],["DEPOSIT","4","b","500"],["PAY","5","b","200"],["MERGE_ACCOUNTS","6","a","b"],["GET_PAYMENT_STATUS","7","a","payment1"],["GET_PAYMENT_STATUS","8","b","payment1"],["TOP_SPENDERS","9","2"],["GET_BALANCE","10","a","4"],["GET_BALANCE","11","a","5"],["GET_BALANCE","86400005","a","86400005"]]return = ["true","100","true","500","payment1","true","IN_PROGRESS","","a(200)","600","400","404"]

After b is absorbed, its payment is queried through a and its outgoing total belongs to a. The inherited history totals both lineages, and the pending cashback is later credited to a.

Constraints

  • 1 <= queries.length <= 2000.
  • External timestamps are unique, strictly increasing integers from 1 through 10^9.
  • Every query uses one valid operation shape described above, and 1 <= timeAt <= timestamp.
  • Account identifiers match [a-z][a-z0-9_]{0,19}.
  • Amounts are positive integers at most 10^9, and every balance and outgoing total fits in a signed 64-bit integer.
  • 1 <= n <= 10^5 for TOP_SPENDERS.

More Airbnb problems

See Airbnb hiring insights
public String[] processBankingQueries(String[][] queries) {
    // Write your code here.
}
queries[["CREATE_ACCOUNT","1","alice"],["CREATE_ACCOUNT","2","bob"],["DEPOSIT","3","alice","1000"],["TRANSFER","4","alice","bob","250"],["TOP_SPENDERS","5","2"]]
expected["true", "true", "1000", "750", "alice(250),bob(0)"]
Checking account…