Free preview

Why this matters: everyone has "implement an LRU cache" filed away as a LeetCode exercise, and that's exactly the trap. The interview version is a library design round: the API and its promises are the product, and half the scoreable decisions — what capacity means, whether a read refreshes recency, what an update does at the limit — are made in the requirements conversation, before a single node gets linked.

The prompt, as given

Design an in-memory cache library.

Other services will embed your library directly in their process: they put values in, get them back, and trust the cache to stay within a capacity bound by evicting something when it must.

Notice what's missing: what "capacity" is measured in, which operations exist, what eviction means, what happens on an update. The candidate who starts drawing a hash map and a linked list is answering a question the interviewer hasn't asked yet. The candidate who asks the right six questions is already scoring.

The questions, and why each one matters

"What does capacity mean — entries or bytes?" This one question splits the design in two. An entry count means the cache can count; a byte budget means someone has to know how big a value is, and that someone is probably not your library. Pin it first, because everything about eviction timing hangs on it.

"Which operations, exactly?" Get, put, remove — and just as important, what's not there. No iteration and no bulk operations means your internal ordering never has to be exposed, which is freedom you'll spend later.

"Does a read count as a use?" The heart of "least recently used." If get refreshes an entry's standing, your reads are writes to the recency bookkeeping — that's a real structural consequence, not a nicety. And the twin question: does updating an existing key count as a use too?

"When does eviction actually happen?" The precise trigger matters: on inserting a new key at capacity? On every put? Does updating an existing key ever evict? A crisp answer here is the difference between an eviction path you can enforce invariants around and one that fires "whenever."

"Are null values allowed?" Sounds pedantic, is not: if null can be a stored value, then get returning null is ambiguous between miss and stored nothing, and your API needs a second channel. Banning nulls buys an unambiguous miss signal for free.

"Is this concurrent?" Ask so you can name the assumption out loud. A single-threaded v1 is a perfectly good design round — silently assuming it is not.

"Does anyone need to know how the cache is doing?" Operators almost always want a hit-rate readout. If stats are in scope, hits and misses need a home and a definition — deciding what counts as a hit is API design, not an afterthought.

The requirement set this chapter builds against

Capacity      maximum ENTRY COUNT, fixed at construction
Operations    get(key), put(key, value), remove(key) — no iteration
Recency       get refreshes an entry's standing;
              put on an existing key updates the value AND refreshes
Eviction      only when a put of a NEW key would exceed capacity;
              victim = least recently used; updates never evict
Null values   disallowed — get returning null means miss, always
Stats         hit/miss counters with a hit-rate readout
Threading     single-threaded (stated assumption)

The design latent in this table: recency refresh on every get means the "used" bookkeeping sits on the hot read path, so it had better be O(1). The new-key-only eviction trigger means put has two genuinely different paths. And the stats requirement means "hit" needs a definition your counters can enforce.

As with every chapter in this course: a live interviewer's answers may differ. Maybe their capacity is a byte budget, maybe updates don't refresh. The skill is the conversation — ask the questions for these reasons, and a different answer sheet just steers the same method to a slightly different design.

Key takeaway

The cache round is won at the API before it's won at the data structure. Pin what capacity counts, the exact get/put/remove semantics — does a read refresh recency, does an update ever evict — the null policy that keeps the miss signal unambiguous, the threading assumption, and whether stats are in scope. This chapter builds against one representative answer set; the questions, not the answers, are the reusable part.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue