Implement GPU credit ledger
Company: OpenAI
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: This question evaluates a candidate's ability to design efficient stateful systems and algorithmic data structures for tracking per-tenant resource balances, including handling idempotency, negative balance policies, concurrency, and persistence.
Constraints
- 0 <= len(init_events), len(operations) <= 2 * 10^5
- -10^9 <= delta <= 10^9
- Average-case O(1) time is expected for each get/apply after O(n) initialization
- If an eventId repeats, it represents the same logical event; replays must be idempotent
Examples
Input: ([('e1', 'tenantA', 10), ('e2', 'tenantA', -3), ('e3', 'tenantB', 5)], [('get', 'tenantA'), ('get', 'tenantB'), ('apply', ('e4', 'tenantA', 2)), ('apply', ('e5', 'tenantB', -6)), ('get', 'tenantB'), ('apply', ('e6', 'tenantA', -4)), ('get', 'tenantB')])
Expected Output: [7, 5, True, False, 5, True, 5]
Explanation: After initialization, tenantA has 7 and tenantB has 5. Adding 2 to tenantA succeeds. Deducting 6 from tenantB fails because it would make the balance negative. Deducting 4 from tenantA later succeeds.
Input: ([], [('get', 'ghost'), ('apply', ('x1', 'ghost', -3)), ('get', 'ghost'), ('apply', ('x1', 'ghost', -3)), ('apply', ('x2', 'ghost', 4)), ('get', 'ghost')])
Expected Output: [0, False, 0, False, True, 4]
Explanation: Unknown tenants start at 0. The first deduction is rejected, and repeating the same eventId returns the same False result. A later positive event succeeds, leaving balance 4.
Input: ([('i1', 'gpu', 5), ('i1', 'gpu', 5), ('i2', 'gpu', -7), ('i3', 'gpu', -2)], [('get', 'gpu'), ('apply', ('i2', 'gpu', -7)), ('apply', ('i1', 'gpu', 5)), ('apply', ('i4', 'gpu2', 1)), ('get', 'gpu2'), ('apply', ('i5', 'gpu', -3)), ('get', 'gpu')])
Expected Output: [3, False, True, True, 1, True, 0]
Explanation: During initialization, i1 is applied once, its duplicate does nothing, i2 is rejected, and i3 succeeds. Later duplicates of i2 and i1 return their original results. A new tenant gpu2 can be credited from 0.
Solution
def solution(init_events, operations):
balances = {}
event_result = {}
def process_event(event):
event_id, tenant_id, delta = event
if event_id in event_result:
return event_result[event_id]
new_balance = balances.get(tenant_id, 0) + delta
accepted = new_balance >= 0
if accepted:
balances[tenant_id] = new_balance
event_result[event_id] = accepted
return accepted
for event in init_events:
process_event(event)
result = []
for op in operations:
if op[0] == 'get':
tenant_id = op[1]
result.append(balances.get(tenant_id, 0))
elif op[0] == 'apply':
event = op[1]
result.append(process_event(event))
else:
raise ValueError('Unknown operation type')
return resultTime complexity: O(len(init_events) + len(operations)) average. Space complexity: O(T + E), where T is the number of tenants seen and E is the number of distinct eventIds seen.
Hints
- Use one hash map for current balances by tenantId, and another hash map for eventId -> previous result.
- Before mutating a balance, compute the projected new balance and reject the event if it would drop below zero.