Data Structures Topic
Tries (Prefix Trees)
Master tries: fast string search, prefix matching, and autocomplete. Learn when to use tries for text-based problems and dictionary operations.
Tries (Prefix Trees)
Why This Matters
A trie (pronounced "try") is a tree-like data structure optimized for storing and searching strings. Unlike hash tables or binary search trees, tries excel at prefix-based operations. Each node represents a character, and paths from root to leaf spell out words.
This matters because tries solve problems that other data structures struggle with. Need to find all words starting with "pre"? A hash table requires checking every word. A trie can do this in O(m) time where m is the prefix length, regardless of dictionary size. This makes tries perfect for autocomplete, spell checkers, IP routing tables, and dictionary problems.
In interviews, trie problems test whether you can recognize when prefix matching is the core requirement. Many engineers reach for hash tables or arrays, but tries provide better time complexity for prefix queries. Real-world systems use tries extensively: search engines use them for query suggestions, routers use them for longest prefix matching, and text editors use them for code completion.
What Engineers Usually Get Wrong
Most engineers think "tries are just trees with characters." While true structurally, the real power comes from how tries organize data by prefixes. Engineers often implement tries without considering space optimization—a basic trie can use significant memory, especially with large character sets (like Unicode).
Engineers also confuse tries with hash tables. Hash tables are better for exact lookups, but tries excel at prefix matching. If you need "find all words starting with 'cat'", a trie is O(m) while a hash table is O(n) where n is total words.
Another common mistake is not handling deletion correctly. Deleting a word from a trie requires careful node cleanup—you can't just remove the leaf node if it's part of another word's path. This requires tracking whether a node marks the end of a word and whether it has children.
How This Breaks Systems in the Real World
A search engine was using a hash table to store search suggestions. When users typed "java", the system needed to find all queries starting with "java" (like "java tutorial", "javascript", "java vs python"). The hash table required scanning all stored queries, which became O(n) and slow as the database grew to millions of queries. The fix? Switch to a trie. Now prefix queries are O(m) where m is the typed prefix length, making autocomplete instant even with millions of stored queries.
Another story: A network router was using a simple array to store IP routing rules. When a packet arrived, the router needed to find the longest matching prefix. With an array, this required checking every rule (O(n)). As routing tables grew, packet forwarding became a bottleneck. The fix? Use a trie (specifically a compressed trie/radix tree). Longest prefix matching became O(m) where m is the IP address length (32 bits for IPv4), making routing fast and scalable.
What is a Trie?
A trie is a tree where each node represents a character, and paths from root to leaf nodes spell out words. The root represents an empty string, and each edge represents a character.
Structure
(root)
/ | \
a b c
/| | |
p t a a
/ | | |
p e t t
| |
l e
|
e
This trie stores: "apple", "ate", "bat", "cat"
Key Properties
- Prefix sharing: Words with common prefixes share nodes
- Fast prefix search: Finding all words with a prefix is O(m) where m is prefix length
- Space efficient for many similar strings: Shared prefixes reduce storage
- Character-based: Each node typically has up to 26 children (for lowercase English)
Trie Implementation
Basic Trie Node
1
Advanced Operations
Find All Words with Prefix
1
Delete Word from Trie
1
Common Pitfalls
- Not marking end of word: Forgetting to set
isEndOfWord = truecauses search to fail even when word exists - Incorrect deletion: Deleting nodes that are part of other words breaks the trie
- Space inefficiency: Using arrays of size 26 for each node wastes space when most children are null
- Case sensitivity: Not handling uppercase/lowercase consistently causes search failures
- Empty string handling: Not handling empty string as valid input causes edge case bugs
Failure Stories You'll Recognize
A spell checker was using a hash table to store dictionary words. When users typed "appl", the system needed to suggest "apple", "apply", "application". The hash table couldn't efficiently find words by prefix, so it scanned all words (O(n)). With a 100,000 word dictionary, this was slow. The fix? Use a trie. Prefix suggestions became O(m) where m is typed length, making suggestions instant.
Another story: A service was building an autocomplete feature. It stored all queries in a database and used SQL LIKE 'prefix%' queries. As the database grew, these queries became slow (full table scans). The fix? Build a trie in memory from frequently used queries. Autocomplete became O(m) instead of O(n), making it fast enough for real-time suggestions.
What Interviewers Are Really Testing
- Recognition: Can you identify when prefix matching is the core requirement?
- Space-time trade-offs: Do you understand tries use more space but enable faster prefix queries?
- Tree traversal: Can you implement DFS for collecting words with a prefix?
- Edge cases: Do you handle empty strings, single characters, and deletion correctly?
- Alternatives: Can you explain when hash tables or BSTs might be better?
Interview Questions
Beginner
- Implement a trie with insert, search, and startsWith operations
- Find if a word exists in a trie
- Count how many words start with a given prefix
Intermediate
- Find all words with a given prefix
- Delete a word from a trie
- Find the longest common prefix of all words in a trie
- Implement autocomplete using a trie
Senior
- Implement a compressed trie (radix tree) to save space
- Design a search engine autocomplete system using tries
- Implement a trie that supports wildcard matching (e.g., "c*t" matches "cat", "cut")
- Optimize trie for memory usage when character set is large (Unicode)
What's next?
Keep exploring
Structure choice drives complexity. Revisit the hub and connect this topic to one you will use in coding rounds.