Tries — Master Recap and Interview Cheatsheet

Sanjeev SharmaSanjeev Sharma
5 min read

Advertisement

Tries Master Cheatsheet

Quick-reference for every trie pattern, template, and decision covered in this series.

Core Operations Complexity

OperationTimeSpace
Insert wordO(L)O(L * 26) array, O(L) hashmap
Search wordO(L)O(1)
Prefix checkO(L)O(1)
Word Search IIO(MN3^L) prunedO(sum of word lengths)
Max XOR pairO(32*n)O(32*n)

Standard Trie Template

class TrieNode:
    def __init__(self):
        self.children = {}   # char → TrieNode (or [None]*26 for lowercase)
        self.is_end = False  # True when a complete word ends at this node
        # Optional extras:
        # self.count = 0     # words passing through (for prefix count)
        # self.word = ""     # full word (for Word Search II recovery)
 
class Trie:
    def __init__(self):
        self.root = TrieNode()
 
    def insert(self, word):
        node = self.root
        for c in word:
            if c not in node.children:
                node.children[c] = TrieNode()
            node = node.children[c]
        node.is_end = True
 
    def search(self, word):
        node = self.root
        for c in word:
            if c not in node.children:
                return False
            node = node.children[c]
        return node.is_end   # must check is_end for exact match
 
    def starts_with(self, prefix):
        node = self.root
        for c in prefix:
            if c not in node.children:
                return False
            node = node.children[c]
        return True   # no is_end check for prefix

Binary Trie (XOR) Template

def insert_bit(root, n):
    node = root
    for bit in range(31, -1, -1):
        b = (n >> bit) & 1
        if b not in node.children:
            node.children[b] = {}
        node = node.children[b]
 
def max_xor_query(root, x):
    node = root
    xr = 0
    for bit in range(31, -1, -1):
        b = (x >> bit) & 1
        want = 1 - b   # prefer opposite bit to maximize XOR
        if want in node:
            xr = (xr << 1) | 1
            node = node[want]
        else:
            xr <<= 1
            node = node[b]
    return xr

Word Search II Template (Trie + Grid DFS)

def findWords(board, words):
    # Build trie with word stored at end nodes
    root = TrieNode()
    for word in words:
        node = root
        for c in word:
            if c not in node.children:
                node.children[c] = TrieNode()
            node = node.children[c]
        node.word = word   # store word at end for O(1) recovery
 
    result = []
    rows, cols = len(board), len(board[0])
 
    def dfs(r, c, node):
        if not (0 <= r < rows and 0 <= c < cols): return
        ch = board[r][c]
        if ch == '#' or ch not in node.children: return
        next_node = node.children[ch]
        if next_node.word:
            result.append(next_node.word)
            next_node.word = None   # avoid duplicates
        board[r][c] = '#'   # mark visited
        for dr, dc in [(-1,0),(1,0),(0,-1),(0,1)]:
            dfs(r+dr, c+dc, next_node)
        board[r][c] = ch    # restore
 
    for r in range(rows):
        for c in range(cols):
            dfs(r, c, root)
    return result

Decision Guide

NeedUse
Prefix searchTrie (HashSet cannot prefix-query)
Multiple words in gridTrie + Grid DFS (Word Search II)
Autocomplete suggestionsTrie + sorted lists at each node
Max/Min XORBinary Trie (bit by bit, MSB first)
Suffix matchingReversed Trie
Count words with prefixTrie with count field
Combined prefix + suffixConcatenate "suf#pref" as trie key

Problem Index

#ProblemKey Trick
01Implement TrieBasic insert/search/prefix
02Design Add Search WordsWildcard DFS with '.'
03Word Search IITrie pruning in grid DFS
04Replace WordsFirst match = shortest root
05Maximum XOR Two NumbersBinary trie greedy opposite bit
06Search SuggestionsSort + bisect or trie lists
07Longest Word in DictionaryOnly traverse is_end nodes
08Palindrome PairsHashMap prefix/suffix check
09Stream of CharactersReverse trie + active nodes
10Prefix and Suffix Searchsuf#pref concatenated key
11Sum of Prefix Scorescount field at each trie node
12Concatenated WordsWord break DP + word set
16Max XOR with ElementOffline sort + binary trie
18Aho-CorasickMulti-pattern with failure links

Key Takeaways

  • A trie node has exactly two components: children and is_end — everything else is optional metadata for specific problems.
  • search checks both path existence AND is_end = True; startsWith checks path existence only — forgetting is_end in search is the most common trie bug.
  • Binary trie inserts numbers bit by bit from MSB; XOR queries greedily take the opposite bit at each level to maximize XOR.
  • Word Search II uses a trie to prune DFS — when the current board path diverges from all trie paths, stop recursing immediately.
  • The count field at each node enables O(L) prefix count queries without DFS — useful for LC 2185 and LC 2416.
  • Space: array children ([None]*26) use O(26 * nodes) space regardless of words; dict children use O(actual_children * nodes).
  • Every trie interview problem is a variation of five core patterns: basic CRUD, grid DFS, count/delete, binary XOR, or autocomplete.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading