Progressive Banking System with Cashback
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 returnstruewhen the account is created andfalsewhen an active account withaccountIdalready exists.deposit(timestamp, accountId, amount)deposits the given amount into the specified account and returns its resulting balance. It returnsnullwhen 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 returnsnullwhen 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 identifierpaymentK, and schedulesfloor(amount * 2 / 100)cashback fortimestamp + 86400000. A failed payment returnsnulland does not consume an identifier.getPaymentStatus(timestamp, accountId, payment)returnsIN_PROGRESSbefore that payment's cashback is processed andCASHBACK_RECEIVEDafterward. It returnsnullwhen the account or payment does not exist, or when the payment belongs to a different current account lineage.
Level 4
mergeAccounts(timestamp, accountId1, accountId2)mergesaccountId2intoaccountId1. It returnsfalseif the identifiers are equal or either active account is missing; otherwise it returnstrue.- 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
accountId2is 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 attimeAt, or after the latest earlier activity when nothing happened exactly then. It returnsnullifaccountIdis not active at the query timestamp or if that surviving account did not yet exist attimeAt.- 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, andGET_BALANCE. - Serialize booleans as
trueorfalse, numbers in base 10, and every conceptualnullas the empty string. - Serialize
TOP_SPENDERSby 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
1through10^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^5forTOP_SPENDERS.