PracHub
QuestionsCoachesLearningGuidesInterview Prep

Quick Overview

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.

  • Medium
  • OpenAI
  • Coding & Algorithms
  • Software Engineer

Implement GPU credit ledger

Company: OpenAI

Role: Software Engineer

Category: Coding & Algorithms

Difficulty: Medium

Interview Round: Technical Screen

You manage a GPU pool with per-tenant credits. Given a list/stream of events where each event adjusts a tenant’s credit balance by a signed integer (positive = add credit, negative = deduct credit), implement three functions: ( 1) init(events): initialize internal state by applying the given ordered events; ( 2) getBalance(tenantId): return the current credit balance for the specified tenant; ( 3) applyEvent(event): process a new single event and update state. Define the event schema (tenantId, delta, optional timestamp/id), decide whether to reject events that would drive balances below zero or allow negatives, and handle idempotency if event ids repeat. Aim for O( 1) average time per operation after O(n) initialization, and discuss data structures, concurrency considerations, and how you would persist state for crash recovery.

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.

Build an **in-memory credit ledger** for a shared GPU pool. Each event changes exactly one tenant's credit balance, and every event must be applied **at most once** even if it is replayed. ## Event schema An event is a triple **`(eventId, tenantId, delta)`**: - **`eventId`** — a unique identifier used for idempotency. - **`tenantId`** — the tenant whose balance changes. - **`delta`** — a signed integer; a positive value **adds** credits, a negative value **deducts** credits. ## Business rules 1. **Non-negative balance.** A tenant's balance may never drop below `0`. If applying an event would make the resulting balance negative, **reject** that event and leave the balance unchanged. 2. **Idempotency by `eventId`.** Each `eventId` is processed **exactly once**. The first time an `eventId` is seen, it is evaluated under rule 1 and produces an accept/reject result. If the **same `eventId`** is ever seen again, it must **not** change state again — instead, return the **same** accept/reject result that was produced the first time, without re-evaluating it against the current balance. 3. **Initialization.** The initial events are applied **in order** using the exact same rules above (so an init event can be rejected for going negative, and a repeated init `eventId` is deduplicated). 4. **Unknown tenant.** Reading the balance of a tenant that has never had an accepted event returns `0`. ## Function to implement ```python def solution(init_events, operations): ... ``` - **`init_events`** — the ordered list of initial events to seed the ledger (the list passed to `init`). Each item is an `(eventId, tenantId, delta)` triple. - **`operations`** — an ordered list of later actions. Each action is one of: - **`('get', tenantId)`** — read a balance. - **`('apply', (eventId, tenantId, delta))`** — apply an event. First seed the ledger by processing every item in `init_events` (rules 1–3). Then process the `operations` in order. ## Output Return a **list** of outputs, one entry per item in `operations`, in order: - For **`('get', tenantId)`**, append the tenant's current integer balance (`0` if the tenant is unknown). - For **`('apply', event)`**, append **`True`** if the event is accepted, or **`False`** if it is rejected. If the event's `eventId` is a duplicate of one already processed (in `init_events` or in an earlier operation), append the **same** boolean result produced the first time that `eventId` was processed. `('get', ...)` operations produce no state change; they only read. ## Constraints - `0 <= len(init_events), len(operations) <= 2 * 10^5` - `-10^9 <= delta <= 10^9` - Average-case **O(1)** time is expected per `get`/`apply` after O(n) initialization. - A repeated `eventId` represents the same logical event; replays must be idempotent. ## Follow-up (discussion only, not implemented) Be ready to explain your O(1)-average data structures, how you would make updates thread-safe, and how you would persist the ledger for crash recovery (for example, a write-ahead log plus periodic snapshots).

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.

Hints

  1. Use one hash map for current balances by tenantId, and another hash map for eventId -> previous result.
  2. Before mutating a balance, compute the projected new balance and reject the event if it would drop below zero.
Last updated: Apr 23, 2026

Loading coding console...

PracHub

Master your tech interviews with 8,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities
  • Student Access

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.

Related Coding Questions

  • Infection Spread Simulation with Death Threshold - OpenAI (medium)
  • Spreading Contagion on a Grid - OpenAI (medium)
  • Streaming Entropy with Numerical Stability - OpenAI (hard)
  • Implement a Distributed Rate Limiter - OpenAI (medium)
  • Compute Plant Infection Time - OpenAI (medium)