Skip to main content
GuideDesignLow level designObject oriented design

Low-Level Design Interview Questions — OOD patterns that repeat every week

A practical guide to low-level design and object-oriented design interviews: rate limiters, hit counters, file systems, autocomplete, and the talk-track that makes your design feel deliberate.

Fin·Apr 8, 2026·7 min read
StrongYes tip

Most low-level design rounds are not mini system design. They are API, data-structure, and state-management rounds. If you can name the operations, state the invariants, and keep mutation in one place, you are usually on the right track.

Low-level design interview questions sit in an awkward middle. They are not raw LeetCode. They are not a 45-minute distributed systems deep dive either. Interviewers want to see whether you can model a small system cleanly, choose the right data structures, and explain why your objects are shaped the way they are.

The same prompts keep showing up: rate limiters, hit counters, stacks with extra operations, file systems, autocomplete, tic-tac-toe, parking lots, and similar "design a small thing" questions. The names change. The underlying patterns do not.

This category has grown in interview frequency partly because it bridges the gap between raw algorithm skill and system design judgment. As Interviewing.io's analysis of interview outcomes notes, candidates who can clearly articulate design decisions tend to outperform those who just write working code. LLD rounds test exactly that articulation.

What low-level design is actually testing

A good object-oriented design answer usually proves four things:

  1. You can define the operations before you write classes.
  2. You can keep the core invariant obvious.
  3. You can pick storage that matches the promised complexity.
  4. You can leave one sane extension point without turning the answer into framework theater.

The trap is starting from class diagrams. Start from the API instead. Ask: what must this object do, what data must stay true after every call, and what time bounds matter?

If you do that, the class list often becomes boring in a good way. This mirrors what Martin Fowler calls "Tell, Don't Ask" -- design the operations first, and the data follows.

The three question families that repeat

Diagram
Rendering diagram...

1. Time-window objects

These questions look different on the surface, but the core job is the same: keep recent events and throw away stale ones.

Common examples:

The pattern is simple:

  • keep one queue or map of recent events
  • evict old entries before answering
  • store only the data needed for the next operation

If the prompt says "last 5 minutes," "10 second cooldown," or "sliding recent window," you should already be thinking queue plus cleanup.

TS
class Logger { private nextAllowed = new Map<string, number>(); shouldPrintMessage(timestamp: number, message: string): boolean { const allowedAt = this.nextAllowed.get(message) ?? -Infinity; if (timestamp < allowedAt) return false; this.nextAllowed.set(message, timestamp + 10); return true; } }

Why this works:

  • the invariant is clear: nextAllowed[message] is the earliest timestamp that can pass
  • each call does O(1) work
  • the storage choice follows directly from the API

That is the talk-track you want in the interview. Not just "here is a map," but "here is the state I must preserve after every call."

2. Stateful boards, counters, and augmented containers

This family rewards one move: store the aggregate state that lets you answer fast later.

Common examples:

  • Design Tic-Tac-Toe
  • Insert Delete GetRandom O(1)
  • Min Stack
  • Maximum Frequency Stack

These are not hard because the APIs are huge. They are hard because brute force is easy to write and too slow to keep.

For tic-tac-toe, you do not rescan the whole board after every move. You keep row counts, column counts, and the two diagonals.

TS
class TicTacToe { private rows: number[]; private cols: number[]; private diag = 0; private antiDiag = 0; constructor(private readonly n: number) { this.rows = Array(n).fill(0); this.cols = Array(n).fill(0); } move(row: number, col: number, player: 1 | 2): number { const delta = player === 1 ? 1 : -1; this.rows[row] += delta; this.cols[col] += delta; if (row === col) this.diag += delta; if (row + col === this.n - 1) this.antiDiag += delta; if ( Math.abs(this.rows[row]) === this.n || Math.abs(this.cols[col]) === this.n || Math.abs(this.diag) === this.n || Math.abs(this.antiDiag) === this.n ) return player; return 0; } }

This is the same design move as GetRandom O(1): precompute or maintain the right state so future operations stay cheap.

When interviewers push on follow-ups, they usually ask about deletion, update, or duplicate handling. That is another signal that they care more about invariant discipline than fancy inheritance.

3. Hierarchies, text systems, and small APIs

This family asks whether you can model nested state without losing the plot.

Common examples:

The winning pattern is usually:

  • keep the storage tree simple
  • separate traversal or parsing from mutation
  • make each node own local metadata only

For file system questions, the mistake is building too many abstractions before you know the supported operations. For autocomplete, the mistake is talking vaguely about tries without stating what is stored at each node and how suggestions are ranked.

A calm answer sounds like this:

  • "Each directory node owns a map of child name to node."
  • "Each trie node stores children plus the top phrases for that prefix."
  • "Encode/decode is a serializer problem, so I want one reversible format and one parser."

That is enough to sound deliberate. You do not need an enterprise architecture lecture.

A sane interview talk-track

When you feel yourself drifting, come back to this script:

  1. Clarify the API. Example: add, remove, get, search, move, list.

  2. State the invariant. Example: "This map always points to the current index of each value."

  3. Choose the storage. Example: "I need O(1) lookup plus O(1) delete, so I want an array plus hash map."

  4. Walk one example. Example: insert twice, delete once, or move along a path.

  5. Name one extension. Example: "If we later need per-user quotas, I would wrap the limiter state by key."

That last step matters. It shows you can think ahead without overbuilding the first version.

Common mistakes in low-level design rounds

Starting with classes instead of operations

If you draw five classes before you know what methods exist, you are guessing. Start from the API and work backward.

Letting multiple objects mutate the same truth

One owner is calmer. If both Board and Game update win state, bugs creep in fast.

Ignoring delete and update cases

Many LLD bugs appear after the first follow-up. If your design only works for append-only state, say so and then patch it.

Chasing abstractions too early

Do not build BaseVehicleFactoryManagerStrategy because the prompt mentioned a parking lot. Clean, direct objects beat enterprise-looking answers almost every time.

A strong practice ladder

If you want a compact low-level design practice set, do these in order:

  1. Cloudflare Rate Limiter Small API, clean invariant, almost no boilerplate.

  2. Find Median from Data Stream Great warm-up for streaming state and two-heap bookkeeping.

  3. Time Based Key-Value Store Same family, but slightly richer timestamp eviction logic.

  4. LRU Cache The classic augmented-container problem.

  5. Design Twitter Good test of aggregate state instead of rescanning everything.

  6. Design Add and Search Words Data Structure Nested state plus API modeling.

  7. Min Stack Forces you to think carefully about dual data structures.

  8. Implement Trie (Prefix Tree) Harder because ranking, text state, and trie modeling all show up at once.

If you can explain those eight cleanly, you are in good shape for most object-oriented design interview questions.

The real grading rubric

Interviewers are usually scoring some version of this:

  • Does the API make sense?
  • Do the data structures match the required operations?
  • Are the invariants explicit?
  • Can you handle follow-ups without restarting from scratch?
  • Does your code stay readable while state changes?

This aligns with how Google's engineering practices describe code review standards: reviewers look for clarity, correctness, and maintainability over cleverness. The same rubric applies in LLD interviews.

That is good news. You do not need a magical answer. You need a design that stays stable under pressure.

Practice Design.

Explain your thinking like you're in the interview.

Practice with Fin or Coco
Source note

Fin and Coco are StrongYes editorial personas from the Council of Ternary Vertices — a trinary-star animal civilization that studies Earth's coding-interview process. Anecdotes map animal-universe experience to human interview mechanics; they are NEVER human-career claims. External citations link to public primary sources.

StrongYes editorial guide grounded in the repo's 14 DESIGN-tagged interview problems plus public low-level-design and object-oriented-design question banks.

Last verified Apr 8, 2026.

Practice Design.

Reading builds recognition. Explaining builds recall. Run these problems with Fin or Coco.