Reported November 2023
Rampdesign

Banking System with Accepted Transfers, Part 2: Activity Ranking

Reported by candidates from Ramp's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Ramp OA. Under 2s to a working solution.
Founder's read

Ramp reportedly served this banking system OA in November 2023, and the Part 2 level is a design problem in disguise. Strip the story and you're keeping a map from accountId to balance and a second number, total activity, then sorting on demand. No fancy data structure needed. The only thing that burns candidates is the output format and the tie-break. If you blank on the exact string building, StealthCoder runs invisibly as a safety net during the live OA. But the logic here is small, so read it carefully and you won't need it.

The problem

Implement a simplified banking system. The assessment is cumulative: after unlocking a new level, every operation from the current and previous levels remains available.
Query and Output Rules
Each query calls exactly one operation and includes a stringified millisecond timestamp.
Timestamps are unique, lie between 1 and 10^9, and appear in strictly increasing order.
Return one string result for every query, in input order.
Return the empty string when an operation has no successful scalar result, exactly as specified below.
Multipart Series
Part 1: Accounts and Payments
Part 2: Activity Ranking
Part 3: Pending Transfer Acceptance
Part 4: Account Merging and Balance History
Level 1: Accounts and Payments
The banking system should support creating new accounts, depositing money, and withdrawing or paying money from accounts.
CREATE_ACCOUNT <timestamp> <accountId> creates a new account with the given accountId if it does not already exist. Return "true" if the account is created and "false" if it already exists.
DEPOSIT <timestamp> <accountId> <amount> deposits amount into the account. Return the account balance after processing the query, or the empty string if the account does not exist.
PAY <timestamp> <accountId> <amount> withdraws amount from the account. Return the account balance after processing the query. Return the empty string if the account does not exist or has insufficient funds.
Level 2: Activity Ranking
The banking system should support ranking accounts by the total value of their transactions.
TOP_ACTIVITY <timestamp> <n> returns the top n accounts with the highest total transaction value, sorted by total value descending and then by accountId alphabetically ascending.
Return one string in the format "<accountId1>(<transactionsValue1>),..., <accountIdN>(<transactionsValueN>)".
Total transaction value is the sum of every processed amount for an account, regardless of how it changes the balance: deposits, payments, and each side of a successfully accepted transfer count.
If fewer than n accounts exist, return all active accounts in the same format.

Function
bankingAcceptedTransfersLevel2(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.

Constraints
1 <= queries.length <= 500.
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 at this part.
Amounts and n are positive base-10 integers. Every balance and transaction total fits in a signed 64-bit integer.
Account identifiers are non-empty strings that do not contain commas or parentheses.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The trick: store two values per account, balance and totalActivity. CREATE_ACCOUNT adds both at zero. DEPOSIT adds the amount to both. PAY only succeeds if balance covers it, then subtracts from balance and adds to activity. A failed PAY must not touch activity. TOP_ACTIVITY collects all accounts, sorts by activity descending then accountId ascending, takes the first n, and joins as id(value) with a comma and a space. With at most 500 queries, sorting on every call is fine, so skip heaps. Common pitfalls: subtracting payments from activity (example 2 shows they add), counting rejected payments, sorting ids with the wrong direction, and returning the wrong separator. Also remember n can exceed the account count, so cap it. Return empty string for missing accounts, never null.

If you see this problem in your OA tomorrow, the play is to recognize the pattern in 30 seconds. StealthCoder buys you that recognition.

If this hits your live OA

You can drill Banking System with Accepted Transfers, Part 2: Activity Ranking cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built by an Amazon engineer who passed his OA cold and still thinks the filter is broken.

Get StealthCoder

Related leaked OAs

⏵ The honest play

You've seen the question. Make sure you actually pass Ramp's OA.

Ramp reuses patterns across OAs. Built by an Amazon engineer who passed his OA cold and still thinks the filter is broken. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Banking System with Accepted Transfers, Part 2: Activity Ranking FAQ

How hard is the Ramp banking system OA really?+

Part 2 is easy to medium. The logic is a hash map and a sort. The difficulty is in the details: empty strings for failures, the exact output format, and the tie-break rule. Most failures come from sloppy reading, not hard algorithms.

What's the trick for TOP_ACTIVITY?+

Track a separate totalActivity per account, distinct from balance. Every successful deposit and payment adds its amount. On a query, sort by activity descending, then accountId ascending, slice the first n, and format as id(value) joined by comma and space.

Do failed payments count toward activity?+

No. Only processed amounts count. A PAY with insufficient funds or a missing account returns an empty string and changes nothing. Check the balance first, and only then update both balance and activity.

Do I need a heap or sorted structure for the ranking?+

No. With at most 500 queries, sorting all accounts on each TOP_ACTIVITY call is plenty fast. A heap adds bug risk for no gain. Keep a plain dictionary and sort a list of entries when the query comes in.

How do I prepare for this in 48 hours?+

Write the Part 1 and Part 2 handlers from scratch once, using the two examples as tests. Then think ahead to cumulative levels, since later parts add transfers and merging. Keep your account record in a small class so new fields are easy to add.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Ramp.

OA at Ramp?
Invisible during screen share
Get it