Compute account balances with rejection and overdraft
Company: Stripe
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
You are given a list of transaction records as strings. Each record has the format:
```
account_id,timestamp,currency,amount
```
- `account_id`: string identifier
- `timestamp`: integer (not guaranteed sorted)
- `currency`: string like `USD`, `EUR`
- `amount`: integer (can be positive for credit or negative for debit)
Maintain balances **per (account_id, currency)**.
## Part 1 — Final balances
Process all transactions and return the final balance for each `(account_id, currency)`.
- Exclude entries whose final balance is exactly `0`.
- Output can be in any order (unless you choose to sort).
## Part 2 — Reject transactions that would go negative
Now process transactions in **increasing `timestamp` order** (tie-breaker can be input order).
A transaction is **rejected** if applying it would make that account’s balance for that `currency` fall below `0`.
- Rejected transactions have no effect.
- Return final non-zero balances as in Part 1.
## Part 3 — Use a platform account for insufficient funds
Add support for a special “platform” account that can cover shortfalls. You are given `platform_account_id` as a parameter.
Processing is still in **timestamp order**. For a debit transaction (negative `amount`) on account `A` in currency `C`:
1. If `A` has enough balance in `C`, apply it normally.
2. Otherwise, attempt to cover the shortfall using the **platform account’s balance in the same currency `C`**:
- Deduct all remaining funds from `A` (bringing it to `0`).
- Deduct the remaining required amount from the platform account.
3. If the platform account also lacks sufficient funds in `C`, **reject** the transaction (no balances change).
Credits (positive `amount`) always apply.
Return final non-zero balances for all accounts (including the platform account if non-zero).
### Constraints (you may assume)
- Up to ~10^5 transactions
- `timestamp` fits in 64-bit integer
- `amount` fits in 64-bit signed integer
Quick Answer: This question evaluates stateful transaction processing and aggregation skills, including per-(account,currency) balance maintenance, timestamp-based ordering, rejection rules, and overdraft coverage via a platform account.
Part 1: Final Balances by Account and Currency
You are given transaction records as strings in the format 'account_id,timestamp,currency,amount'. Compute the final balance for each (account_id, currency) pair by summing all amounts. Timestamps do not matter in this part. Exclude any pair whose final balance is exactly 0. For deterministic grading, return the answer sorted lexicographically by account_id and then currency, with each row formatted as 'account_id,currency,balance'.
Constraints
- 0 <= len(transactions) <= 10^5
- timestamp fits in 64-bit signed integer
- amount fits in 64-bit signed integer
- Each transaction string is well-formed
Examples
Input: (['alice,10,USD,100','bob,12,EUR,40','alice,11,USD,-30','alice,15,EUR,50'],)
Expected Output: ['alice,EUR,50','alice,USD,70','bob,EUR,40']
Explanation: USD and EUR are tracked separately for alice.
Input: (['a,1,USD,10','a,2,USD,-10','b,3,USD,5'],)
Expected Output: ['b,USD,5']
Explanation: Account a ends at 0 USD and is excluded.
Hints
- Use a hash map keyed by (account_id, currency).
- Aggregate first, then filter out zero balances and sort once at the end.
Part 2: Final Balances with Rejected Overdrafts
You are given transaction records as strings in the format 'account_id,timestamp,currency,amount'. Process transactions in increasing timestamp order. If two transactions have the same timestamp, keep their original input order. Maintain balances separately for each (account_id, currency). A transaction is rejected if applying it would make that balance go below 0. Rejected transactions have no effect. Return all non-zero final balances sorted lexicographically by account_id and then currency, using the row format 'account_id,currency,balance'.
Constraints
- 0 <= len(transactions) <= 10^5
- timestamp fits in 64-bit signed integer
- amount fits in 64-bit signed integer
- Each transaction string is well-formed
Examples
Input: (['alice,5,USD,-30','alice,1,USD,100','alice,3,USD,-80','bob,2,EUR,20','bob,4,EUR,-25'],)
Expected Output: ['alice,USD,20','bob,EUR,20']
Explanation: After sorting by time, bob's debit and alice's last debit are both rejected.
Input: (['a,2,USD,-5','a,2,USD,10'],)
Expected Output: ['a,USD,10']
Explanation: Same timestamp uses input order, so the debit is seen first and rejected.
Hints
- Sort by timestamp, but keep the original index so ties follow input order.
- Before applying a debit, check whether current_balance + amount would be negative.
Part 3: Final Balances with Platform Shortfall Coverage
You are given transaction records as strings in the format 'account_id,timestamp,currency,amount' and a special platform_account_id. Process transactions in increasing timestamp order, breaking ties by original input order. Credits always apply. For a debit on account A in currency C: if A has enough funds, apply it normally. Otherwise, try to cover the shortfall from the platform account in the same currency C. If the platform can cover the shortfall, bring A to 0 and deduct the remaining amount from the platform. If the platform also lacks enough funds, reject the transaction and leave all balances unchanged. If the debit is on the platform account itself, it cannot cover itself beyond its own balance; reject it if it would go negative. Return all non-zero final balances sorted lexicographically by account_id and then currency, using the row format 'account_id,currency,balance'.
Constraints
- 0 <= len(transactions) <= 10^5
- timestamp fits in 64-bit signed integer
- amount fits in 64-bit signed integer
- platform_account_id is a string identifier
- Each transaction string is well-formed
Examples
Input: (['platform,1,USD,100','alice,2,USD,30','alice,3,USD,-50'],'platform')
Expected Output: ['platform,USD,80']
Explanation: Alice uses her 30 first, and the platform covers the remaining 20.
Input: (['platform,1,USD,10','alice,2,USD,5','alice,3,USD,-20'],'platform')
Expected Output: ['alice,USD,5','platform,USD,10']
Explanation: The shortfall is 15, but the platform only has 10 USD, so the debit is rejected.
Hints
- For an insufficient debit, compute shortfall = debit_amount - account_balance.
- Only change balances after confirming the platform has enough in the same currency.