TRT
Sign in
mediumAdvanceddesign

Design the data structure behind search autocomplete

Return the top suggestions for a typed prefix quickly, with a trie whose nodes cache their best completions.

TRT practice prompt — not a verified question from a named employer.

The Runtime Theory Team2 min read
Learn it firstTriesPro — members onlyA trie stores strings as paths from a root, one character per edge, so words with a common prefix share nodes. Lookups and prefix queries cost time proportional to the query's length, however many words are stored.

A strong answer

A strong candidate frames Design the data structure behind search autocomplete around the exact memory layout, compiler semantics, and hardware execution model covered in Tries. Return the top suggestions for a typed prefix quickly, with a trie whose nodes cache their best completions.

A hash set answers one question about strings very well: is this exact string stored? It can't answer questions about prefixes: which stored words start with "pro", what is the longest stored word that is a prefix of this URL, can any word in a dictionary be formed by extending what I have so far. For those, the standard tool is the trie, a name taken from retrieval, usually pronounced "try".

A trie stores strings as paths from a root. Each edge is labeled with one character, and each node represents the prefix spelled by the path from the root to it. Inserting a word walks down from the root, following existing edges for as long as they match and creating new nodes for the rest. The last node gets a flag that says a word ends here. Words that share a prefix share the nodes for it: in the trace above, "tea" and "ten" share the path t → e, and "to" shares only t.

In a production interview, always connect the specification rule to its concrete runtime consequence: state what lives on the stack versus the heap or static storage segment, how the compiler or operating system validates alignments, lifetimes, and error codes, and what happens under adversarial or boundary inputs (such as zero-length buffers, integer overflow, concurrent mutation, or partial I/O). Backing your explanation with a small trace of register/memory state transitions immediately separates senior systems engineers from candidates who only memorized syntax.

What the interviewer is listening for

  • Mastery of core invariant: Build a trie with insert, search and prefix search, and state their costs.
  • Mastery of core invariant: Use a trie to drive searches over many words at once, such as autocomplete and grid word search.
  • Mastery of core invariant: Weigh a trie's memory cost against a hash set or sorted array, and know the compressed variants.
  • Hardware and ABI awareness: Explaining how sizes, alignments, calling conventions, or kernel boundaries behave on real 64-bit targets rather than relying on implementation-defined assumptions.
  • Defensive engineering: Naming the exact compiler flags (-Wall -Wextra -Werror), static analyzers, or runtime sanitizers (-fsanitize=address,undefined,thread) that verify correctness in CI.

Common mistakes

  • Explaining only surface syntax without tracing the underlying memory addresses, ownership lifetime, or kernel/user-space state transitions.
  • Assuming undefined behavior (such as signed overflow, uninitialized reads, strict-aliasing violations, or dangling pointers) will "just work" because it passed an unoptimized -O0 debug build.
  • Ignoring return codes, partial reads/writes, alignment padding, or cleanup paths when an allocation or syscall fails midway through a function.

This answer walks

Practice follow-ups

  1. 01How do you update the cached suggestions when a query's count changes?
  2. 02How would you reduce the trie's memory?
  3. 03How would you tolerate a typo in the prefix?
  4. 04How would you split this across machines?

Not started

Sign in to save your learning progress.

Sign in to save