Implement expiring credit ledger
Company: OpenAI
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Technical Screen
Quick Answer: This question evaluates the ability to design efficient time-based data structures and algorithms for managing expiring credits with ordering and tie-breaking rules, testing competencies in event ordering, interval management, and retroactive update handling; it is in the Coding & Algorithms domain and emphasizes practical application of algorithmic and data-structure reasoning. It is commonly asked to verify correctness under out-of-order inserts and queries, to assess performance and complexity analysis for add/charge/get operations, and to require clear specification of time and space complexity for the proposed approach.
Constraints
- 1 <= len(operations) <= 2 * 10^5
- 0 <= amount, time_stamp, expiration <= 10^9
- All `id` values in `add` operations are distinct strings
- A credit is active on [start, end), so it is active at `start` but not active at `end`
- Use 64-bit integer arithmetic in static languages
Examples
Input: [('charge', 45, 6), ('add', 'A', 50, 5, 10), ('balance', 8), ('charge', 15, 7), ('balance', 6), ('add', 'B', 30, 3, 4)]
Expected Output: [45, 20, 15, 35]
Explanation: Evaluate by time: add B at 3, add A at 5, charge 45 at 6 consumes B=30 then A=15, so the balance at time 6 is 35. At time 7, B is expired and charge 15 consumes from A, leaving 20 for the balance at time 8. Outputs are returned in original input order.
Input: [('balance', 1), ('charge', 5, 4), ('charge', 4, 2), ('balance', 3), ('add', 'C', 4, 2, 1)]
Expected Output: [0, 0, 4, 0]
Explanation: At time 1 there is no credit, so balance is 0. At time 2, the add happens before the charge, so the charge gets 4. The bucket is active on [2, 3), so by time 3 it is no longer active, and the later charge at time 4 also returns 0.
Input: [('balance', 5), ('charge', 3, 5), ('add', 'Z', 10, 5, 0)]
Expected Output: [0, 0]
Explanation: A bucket with expiration 0 is active on the empty interval [5, 5), so it is never usable. At timestamp 5, add is considered first, then charge, then balance, but both output-producing operations still see 0.
Input: [('balance', 10), ('add', 'x', 10, 5, 5), ('charge', 10, 11), ('add', 'y', 8, 1, 10), ('charge', 12, 6)]
Expected Output: [6, 0, 12]
Explanation: At time 6, charge 12 uses x first because it expires earlier, then uses part of y, leaving 6 in y. At time 10, x is expired so balance is 6. At time 11, y is also expired, so the charge returns 0.
Input: []
Expected Output: []
Explanation: No operations means no outputs.
Hints
- Think of this as a sweep-line problem: sort all operations by effective execution order on the timeline.
- Maintain the currently active credit buckets in a min-heap keyed by (expiration_end, activation_time, id), and keep a running sum of active remaining credit.