Skip to main content

๐ŸŒณ Trie (Prefix Tree)

Conceptโ€‹

A Trie (pronounced "try") is a tree where each node represents a character, and paths from root to leaf spell out words. It excels at prefix lookups and is far more efficient than HashMap for prefix-related operations.

Words: ["cat", "car", "card", "care", "bat"]

root
/ \
c b
| |
a a
/ \ |
t r t
/|\
d e (end)

When to Useโ€‹

  • Autocomplete / prefix search
  • Check if any word in a list starts with a given prefix
  • Word search in a board (replace HashMap with Trie for efficiency)
  • Longest common prefix
  • Count words with a given prefix

Java Implementationโ€‹

class Trie {
private TrieNode root;

static class TrieNode {
TrieNode[] children = new TrieNode[26];
boolean isEnd = false;
int count = 0; // optional: track how many words pass through
}

public Trie() {
root = new TrieNode();
}

// O(m) โ€” m = word length
public void insert(String word) {
TrieNode curr = root;
for (char c : word.toCharArray()) {
int idx = c - 'a';
if (curr.children[idx] == null) {
curr.children[idx] = new TrieNode();
}
curr = curr.children[idx];
curr.count++;
}
curr.isEnd = true;
}

// O(m)
public boolean search(String word) {
TrieNode node = getNode(word);
return node != null && node.isEnd;
}

// O(m)
public boolean startsWith(String prefix) {
return getNode(prefix) != null;
}

private TrieNode getNode(String s) {
TrieNode curr = root;
for (char c : s.toCharArray()) {
int idx = c - 'a';
if (curr.children[idx] == null) return null;
curr = curr.children[idx];
}
return curr;
}

// Count how many words start with prefix โ€” O(m)
public int countPrefix(String prefix) {
TrieNode node = getNode(prefix);
return node == null ? 0 : node.count;
}
}

Worked Example 1: Word Search II (Trie + Backtracking)โ€‹

Find all words from a dictionary that exist in a 2D board.

public List<String> findWords(char[][] board, String[] words) {
Trie trie = new Trie();
for (String w : words) trie.insert(w);

int m = board.length, n = board[0].length;
Set<String> result = new HashSet<>();

for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
dfs(board, i, j, trie.root, new StringBuilder(), result);
}
}
return new ArrayList<>(result);
}

private void dfs(char[][] board, int r, int c, Trie.TrieNode node,
StringBuilder path, Set<String> result) {
if (r < 0 || r >= board.length || c < 0 || c >= board[0].length
|| board[r][c] == '#') return;

char ch = board[r][c];
Trie.TrieNode next = node.children[ch - 'a'];
if (next == null) return; // no words down this path โ€” PRUNE

path.append(ch);
board[r][c] = '#'; // mark visited

if (next.isEnd) result.add(path.toString());

int[][] dirs = {{0,1},{0,-1},{1,0},{-1,0}};
for (int[] d : dirs) {
dfs(board, r + d[0], c + d[1], next, path, result);
}

board[r][c] = ch; // restore
path.deleteCharAt(path.length() - 1);
}

Worked Example 2: Replace Words (Dictionary Prefix)โ€‹

public String replaceWords(List<String> dictionary, String sentence) {
Trie trie = new Trie();
for (String root : dictionary) trie.insert(root);

StringBuilder sb = new StringBuilder();
for (String word : sentence.split(" ")) {
if (sb.length() > 0) sb.append(' ');
// Walk trie until we hit a word end or exhaust the trie
Trie.TrieNode curr = trie.root;
StringBuilder prefix = new StringBuilder();
boolean replaced = false;
for (char c : word.toCharArray()) {
if (curr.children[c - 'a'] == null) break;
curr = curr.children[c - 'a'];
prefix.append(c);
if (curr.isEnd) { sb.append(prefix); replaced = true; break; }
}
if (!replaced) sb.append(word);
}
return sb.toString();
}

LeetCode Problemsโ€‹

๐ŸŸก Mediumโ€‹

#ProblemKey Idea
208Implement Trie (Prefix Tree)Core Trie implementation
211Design Add and Search Words Data StructureTrie + DFS for '.'
421Maximum XOR of Two Numbers in an ArrayBinary Trie
648Replace WordsTrie prefix match
676Implement Magic DictionaryTrie + fuzzy search
720Longest Word in DictionaryTrie BFS/DFS

๐Ÿ”ด Hardโ€‹

#ProblemKey Idea
212Word Search IITrie + board backtrack
336Palindrome PairsTrie + palindrome check
745Prefix and Suffix SearchDouble Trie