Compute balances, rejections, and platform reserve
Company: TikTok
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates transactional state management, time-ordered stream processing, balance reconciliation, handling of rejected transactions, and modeling inter-account borrowing with platform reserve accounting.
Part 1: Non-zero ending balances
Constraints
- 0 <= len(transactions) <= 200000
- account_name and currency are non-empty strings
- timestamp is an integer
- amount is an integer in the smallest currency unit and may be negative, zero, or positive
- Different currencies for the same account must be tracked separately
Examples
Input: ([('alice', 3, 'USD', 100), ('bob', 1, 'USD', 50), ('alice', 2, 'USD', -20), ('alice', 4, 'EUR', 70), ('bob', 5, 'USD', -50), ('carol', 6, 'USD', 0)],)
Expected Output: [('alice', 'EUR', 70), ('alice', 'USD', 80)]
Explanation: bob and carol end at 0, so they are omitted.
Input: ([('acct', 1, 'USD', -30)],)
Expected Output: [('acct', 'USD', -30)]
Explanation: A negative ending balance is still included if it is non-zero.
Input: ([('x', 1, 'USD', 40), ('x', 2, 'USD', -40), ('x', 3, 'EUR', 10), ('x', 4, 'EUR', -10)],)
Expected Output: []
Explanation: All balances cancel to zero.
Input: ([],)
Expected Output: []
Explanation: Edge case: no transactions.
Hints
- A dictionary keyed by (account_name, currency) is enough to accumulate balances.
- After processing all rows, filter out balances equal to 0 before returning.
Part 2: Reject transactions that would make balance negative
Constraints
- 0 <= len(transactions) <= 200000
- account_name and currency are non-empty strings
- timestamp is an integer; process in ascending timestamp order
- If timestamps tie, preserve the original input order
- amount is an integer in the smallest currency unit
Examples
Input: ([('alice', 3, 'USD', -70), ('alice', 1, 'USD', 100), ('alice', 2, 'USD', -30), ('bob', 4, 'EUR', -10), ('bob', 5, 'EUR', 20), ('bob', 6, 'EUR', -5)],)
Expected Output: (['bob,4,EUR,-10'], [('bob', 'EUR', 15)])
Explanation: alice finishes at 0 and is omitted; bob's first transaction is rejected because it would make balance negative.
Input: ([('a', 1, 'USD', 50), ('a', 1, 'USD', -70), ('a', 1, 'USD', 20)],)
Expected Output: (['a,1,USD,-70'], [('a', 'USD', 70)])
Explanation: All timestamps tie, so input order matters: 50 is applied, -70 is rejected, then 20 is applied.
Input: ([('x', 1, 'USD', 100), ('x', 2, 'EUR', -10), ('x', 3, 'USD', -40), ('x', 4, 'EUR', 15)],)
Expected Output: (['x,2,EUR,-10'], [('x', 'EUR', 15), ('x', 'USD', 60)])
Explanation: USD and EUR balances are tracked separately.
Input: ([],)
Expected Output: ([], [])
Explanation: Edge case: no transactions.
Hints
- Carry each row's original index while sorting so equal timestamps stay in input order.
- A rejected transaction should not change the stored balance at all.
Part 3: Allow borrowing from a platform account and compute max_reserve
Constraints
- 0 <= len(transactions) <= 200000
- account_name, currency, and platform_id are non-empty strings
- timestamp is an integer; process in ascending timestamp order
- If timestamps tie, preserve the original input order
- amount is an integer in the smallest currency unit
- Borrowing is allowed only within the same currency
- The platform account itself cannot borrow
Examples
Input: ([('platform', 1, 'USD', 100), ('alice', 2, 'USD', -30), ('alice', 3, 'USD', 10), ('alice', 4, 'USD', -50), ('alice', 5, 'USD', 100)], 'platform')
Expected Output: ({'USD': 70}, [], [('alice', 'USD', 30), ('platform', 'USD', 100)])
Explanation: alice borrows 30, repays 10, later borrows 50 more, so the peak outstanding reserve in USD is 70.
Input: ([('platform', 1, 'USD', 40), ('bob', 2, 'USD', -50), ('platform', 3, 'USD', -10), ('platform', 4, 'USD', -35), ('bob', 5, 'USD', -20)], 'platform')
Expected Output: ({'USD': 20}, ['bob,2,USD,-50', 'platform,4,USD,-35'], [('platform', 'USD', 10)])
Explanation: bob's first withdrawal is rejected because the platform cannot fund it; the platform's own overdrawn transaction is also rejected.
Input: ([('platform', 1, 'USD', 100), ('platform', 1, 'EUR', 50), ('alice', 2, 'USD', -70), ('bob', 3, 'EUR', -20), ('alice', 4, 'USD', 30), ('bob', 5, 'EUR', 50)], 'platform')
Expected Output: ({'EUR': 20, 'USD': 70}, [], [('bob', 'EUR', 30), ('platform', 'EUR', 50), ('platform', 'USD', 60)])
Explanation: Reserve is tracked separately per currency. alice's USD debt is partially repaid; bob fully repays EUR debt and keeps the remainder.
Input: ([], 'platform')
Expected Output: ({}, [], [])
Explanation: Edge case: no transactions.
Hints
- Track two separate things for non-platform accounts: cash balance and outstanding debt.
- When money flows into a borrower account, repay debt first; max_reserve should be based on total outstanding debt, not on platform cash.