Trie Data Structure: Complete Interview Guide
Master the trie (prefix tree) for autocomplete, spell checking, and word search problems. One of the most underrated data structures in interview prep.
Saved on this browser only. No account needed.
What is a Trie?
A trie (pronounced "try") is a tree-like data structure that stores strings character by character. Each node represents a single character, and paths from root to leaf (or marked nodes) represent complete words. The key advantage: prefix lookups are O(m) where m is the prefix length, regardless of how many words are stored.
When to Use a Trie
- Autocomplete / typeahead: Find all words starting with a prefix
- Spell checking: Check if a word exists, suggest corrections
- Word search in grids: Efficiently prune search paths
- IP routing: Longest prefix matching
- Dictionary operations: Insert, search, prefix search in O(m) time
If the problem involves prefixes, word lookups, or building words character by character, think trie.
Basic Trie Implementation
class TrieNode {
children: Map<string, TrieNode> = new Map()
isEndOfWord: boolean = false
}
class Trie {
root: TrieNode = new TrieNode()
// Insert a word - O(m) time, O(m) space
insert(word: string): void {
let node = this.root
for (const char of word) {
if (!node.children.has(char)) {
node.children.set(char, new TrieNode())
}
node = node.children.get(char)!
}
node.isEndOfWord = true
}
// Search for exact word - O(m) time
search(word: string): boolean {
const node = this.findNode(word)
return node !== null && node.isEndOfWord
}
// Check if any word starts with prefix - O(m) time
startsWith(prefix: string): boolean {
return this.findNode(prefix) !== null
}
// Helper: traverse to the node for a given string
private findNode(str: string): TrieNode | null {
let node = this.root
for (const char of str) {
if (!node.children.has(char)) return null
node = node.children.get(char)!
}
return node
}
}Pattern 1: Autocomplete / Prefix Search
Problem: Given a dictionary of words and a prefix, return all words that start with that prefix.
function autocomplete(trie: Trie, prefix: string): string[] {
const results: string[] = []
const node = trie.findNode(prefix)
if (!node) return results
// DFS to collect all words from this node
function dfs(node: TrieNode, path: string) {
if (node.isEndOfWord) {
results.push(path)
}
for (const [char, child] of node.children) {
dfs(child, path + char)
}
}
dfs(node, prefix)
return results
}
// Usage:
// trie has: ["apple", "app", "application", "banana"]
// autocomplete(trie, "app") → ["app", "apple", "application"]Pattern 2: Word Search II (LeetCode 212)
Problem: Given a 2D board of characters and a list of words, find all words that can be formed by adjacent cells (up, down, left, right).
This is where tries shine - instead of searching for each word separately (slow), build a trie from all words and search the grid once.
function findWords(board: string[][], words: string[]): string[] {
const trie = new Trie()
for (const word of words) trie.insert(word)
const results = new Set<string>()
const rows = board.length, cols = board[0].length
function dfs(r: number, c: number, node: TrieNode, path: string) {
if (r < 0 || r >= rows || c < 0 || c >= cols) return
const char = board[r][c]
if (char === '#' || !node.children.has(char)) return
const next = node.children.get(char)!
const newPath = path + char
if (next.isEndOfWord) {
results.add(newPath)
// Don't return - there might be longer words
}
board[r][c] = '#' // mark visited
dfs(r + 1, c, next, newPath)
dfs(r - 1, c, next, newPath)
dfs(r, c + 1, next, newPath)
dfs(r, c - 1, next, newPath)
board[r][c] = char // restore
// Optimization: prune empty branches
if (next.children.size === 0) {
node.children.delete(char)
}
}
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
dfs(r, c, trie.root, '')
}
}
return [...results]
}
// Key insight: trie lets us prune entire search branches.
// Without trie: O(words * cells * 4^wordLen)
// With trie: O(cells * 4^maxLen) - search all words simultaneouslyPattern 3: Design Add and Search Words (LeetCode 211)
Problem: Support adding words and searching with '.' wildcards, where '.' matches any character.
class WordDictionary {
root: TrieNode = new TrieNode()
addWord(word: string): void {
let node = this.root
for (const char of word) {
if (!node.children.has(char)) {
node.children.set(char, new TrieNode())
}
node = node.children.get(char)!
}
node.isEndOfWord = true
}
search(word: string): boolean {
return this.dfs(word, 0, this.root)
}
private dfs(word: string, index: number, node: TrieNode): boolean {
if (index === word.length) return node.isEndOfWord
const char = word[index]
if (char === '.') {
// Wildcard: try all children
for (const child of node.children.values()) {
if (this.dfs(word, index + 1, child)) return true
}
return false
}
if (!node.children.has(char)) return false
return this.dfs(word, index + 1, node.children.get(char)!)
}
}
// addWord("bad"), addWord("dad"), addWord("mad")
// search(".ad") → true (matches all three)
// search("b..") → true (matches "bad")
// search("b.d") → true (matches "bad")Trie Complexity Analysis
Insert
O(m)
m = word length
Search
O(m)
m = word length
Space
O(n × m)
n words, m avg length
Optimization: Array vs Map Children
For lowercase English letters only, use a fixed array of 26 instead of a Map. This is faster (array index vs hash lookup) and uses less memory per node.
class TrieNodeArray {
children: (TrieNodeArray | null)[] = new Array(26).fill(null)
isEndOfWord: boolean = false
}
// Access: node.children[char.charCodeAt(0) - 97]
// 'a' = index 0, 'b' = index 1, ..., 'z' = index 25
// Faster than Map for known alphabet, but wastes space for sparse nodesProblems to Practice
- Implement Trie (LeetCode 208) - Start here. Core insert/search/startsWith
- Word Search II (LeetCode 212) - Hard. Trie + backtracking on grid
- Design Search Autocomplete (LeetCode 642) - Trie with frequency ranking
- Add and Search Word (LeetCode 211) - Trie with wildcard DFS
- Replace Words (LeetCode 648) - Find shortest prefix root
- Maximum XOR (LeetCode 421) - Bitwise trie, advanced
Practice Trie Problems on HireReady
Build muscle memory with spaced repetition. Our FSRS algorithm ensures you review trie problems at the optimal intervals for long-term retention.
Start Practicing Free →Article Details
This guide is part of HireReady's interview prep library and is maintained to reflect current hiring practices.
Further Reading
Keep Reading
Stack Pattern: Complete Interview Guide
Master stack patterns for coding interviews. Learn matching brackets, monotonic stack, expression evaluation, and common LeetCode problems.
Read moreBig O Notation Explained
Complete guide to Big O notation, algorithmic complexity, and performance analysis. Learn to calculate time and space complexity from code with real examples.
Read moreTop K Elements Pattern: Heap Interview Guide
Master the Top K elements pattern using heaps for finding largest/smallest K elements, Kth largest, and frequency problems.
Read more