Tries Solve Prefix Problems That Hash Maps Cannot
When you encounter a problem involving prefixes, autocomplete, or dictionary lookups, there is one data structure that handles it cleanly: the trie. Also called a prefix tree, a trie stores strings character by character in a tree structure, making prefix-based operations blazingly fast.
Trie leetcode problems appear more often in coding interviews than most candidates expect. Companies like Google, Amazon, and Microsoft love them because they test your ability to implement a non-trivial data structure from scratch and then apply it to solve real-world problems.
The good news is that the trie implementation itself is surprisingly simple — roughly 20 lines of code. Once you have the template memorized, you can apply it to a wide range of problems from autocomplete systems to word search grids.
In this guide, you will learn what a trie is, how to implement one, the classic trie LeetCode problems you need to know, and when to reach for a trie versus simpler alternatives.
What Is a Trie? The Prefix Tree Explained
A trie is a tree data structure where each node represents a single character. Paths from the root to any node form prefixes, and paths from the root to nodes marked as "end" form complete words. Unlike a binary tree where each node has at most two children, a trie node can have up to 26 children (for lowercase English letters) or more for extended character sets.
Consider storing the words "app", "apple", and "apt" in a trie. The root branches to "a", which branches to "p", which branches to both another "p" (leading to "app" and "apple") and "t" (forming "apt"). The shared prefix "ap" is stored only once, which is what makes tries space-efficient for sets of strings with common prefixes.
This prefix tree data structure is the backbone of real-world systems you use every day. Search engine autocomplete, phone contact search, spell checkers, and IP routing tables all rely on trie-like structures under the hood.
- Each node represents a single character in the trie
- Paths from root to a node represent prefixes of stored words
- An isEnd (or isWord) flag marks nodes that complete a valid word
- Shared prefixes are stored once, saving space for related words
- Lookup, insert, and prefix search all run in O(L) time where L is the word length
The Trie Implementation Template
The entire trie data structure boils down to two pieces: a TrieNode class and the Trie class with three core methods. A TrieNode holds a map of children (character to TrieNode) and a boolean isEnd flag. The Trie class provides insert, search, and startsWith.
For insert, you walk through each character of the word. If the current node does not have a child for that character, you create a new TrieNode. After processing all characters, you mark the last node with isEnd = true.
For search, you walk through each character. If at any point the character is missing from the children map, the word does not exist — return false. If you reach the end of the word, return the isEnd flag (because the path might exist as a prefix of another word but not as a complete word itself).
The startsWith method is nearly identical to search, except you do not check isEnd at the end. If you successfully walk through all characters of the prefix without hitting a missing child, the prefix exists in the trie.
Every operation runs in O(L) time where L is the length of the word or prefix. Space complexity is O(N * L) in the worst case where N is the number of words and L is the average length, though shared prefixes reduce this significantly in practice.
- 1Create a TrieNode class with a children map (Map<string, TrieNode> or object) and an isEnd boolean defaulting to false
- 2Create a Trie class with a root TrieNode
- 3Implement insert(word): iterate through characters, create nodes as needed, set isEnd = true on the final node
- 4Implement search(word): iterate through characters, return false if a child is missing, return node.isEnd at the end
- 5Implement startsWith(prefix): same as search but return true if you reach the end of the prefix without a missing child
Pro Tip
The entire Trie implementation is ~20 lines — a TrieNode with a children map and isEnd boolean, plus insert/search/startsWith methods. It's one of the easiest advanced data structures to memorize.
Classic Trie LeetCode Problems You Must Know
There is a core set of trie interview problems that appear repeatedly across top tech companies. Mastering these five problems will prepare you for virtually any trie-related question you encounter.
Implement Trie (LeetCode #208) is the foundation. This problem asks you to build the exact data structure described above. It is the perfect starting point because every other trie problem builds on this implementation. Practice until you can write it from memory in under five minutes.
Design Add and Search Words (LeetCode #211) extends the basic trie with wildcard support. The search method must handle "." characters that match any letter, which requires a DFS traversal instead of a simple character-by-character walk. This teaches you how to combine trie structure with recursive backtracking.
Word Search II (LeetCode #212) is the canonical hard trie problem. Given a grid of letters and a list of words, find all words that can be formed by adjacent cells. The brute-force approach runs a separate DFS for each word, but building a trie from the word list lets you search for all words simultaneously during a single grid traversal.
Replace Words (LeetCode #648) asks you to replace words in a sentence with their shortest root from a dictionary. A trie makes this efficient: insert all roots, then for each word in the sentence, walk the trie and return the first complete root you find.
Longest Word in Dictionary (LeetCode #720) requires finding the longest word where every prefix is also a word in the dictionary. Insert all words into a trie, then BFS or DFS to find the longest path where every node along the way has isEnd = true.
- Implement Trie (#208) — Build the core data structure from scratch
- Design Add and Search Words (#211) — Extend trie with wildcard "." matching via DFS
- Word Search II (#212) — Combine trie with backtracking on a 2D grid (hard, frequently asked)
- Replace Words (#648) — Use trie for efficient prefix replacement in strings
- Longest Word in Dictionary (#720) — Find longest word buildable one character at a time
When to Use a Trie vs Hash Set
Not every string problem needs a trie. Understanding when a trie adds value versus when a simpler hash set suffices is a critical skill for interviews. The distinction comes down to one question: do you need prefix operations?
A hash set gives you O(1) average-case lookup for exact matches. If the problem only asks whether a complete word exists in a collection, a hash set is simpler, faster, and uses less memory. Problems like Two Sum or checking for duplicates do not benefit from a trie at all.
A trie wins decisively when the problem involves prefix queries, autocomplete suggestions, wildcard matching, or finding all words that start with a given string. A hash set cannot efficiently answer "give me all words starting with pre" without scanning every entry, while a trie does this in O(prefix length) time.
The autocomplete data structure pattern is a classic trie use case. If you need to return all completions for a partial input, a trie lets you navigate to the prefix node and then collect all descendants — something a hash set simply cannot do efficiently.
- Use a hash set when you only need exact word lookups — O(1) and simpler code
- Use a trie when you need prefix search (startsWith), autocomplete, or wildcard matching
- Trie wins for problems asking "find all words with prefix X" — hash sets require full scan
- Hash set wins for membership checks like "is this word in the dictionary?"
- In interviews, explicitly stating why you chose trie over hash set shows strong problem-solving judgment
Did You Know
Word Search II (#212) is the canonical hard Trie problem — it combines Trie with backtracking on a grid. It's frequently asked at Google and Amazon.
Common Trie Mistakes in Interviews
Even candidates who understand tries conceptually make implementation mistakes under pressure. Knowing the common pitfalls ahead of time will help you avoid them when it counts.
The most frequent mistake is forgetting the isEnd flag. Without it, your search method cannot distinguish between a complete word and a prefix that happens to exist because a longer word was inserted. For example, if you insert "apple", searching for "app" should return false unless "app" was also inserted — and only the isEnd flag makes this distinction.
Another common error is using a fixed-size array of 26 slots (array[26]) when the problem involves characters beyond lowercase English letters. If the input includes uppercase letters, digits, or Unicode characters, a hash map for children is safer and more flexible. The trade-off is that array[26] uses slightly less memory and is marginally faster for pure lowercase problems.
Over-engineering is also a trap. Some candidates reach for a trie on problems where a hash set is the correct and simpler tool. If the problem only requires exact lookups with no prefix operations, building a trie wastes time and adds unnecessary complexity. In an interview setting, picking the right data structure matters as much as implementing it correctly.
- Forgetting isEnd flag — causes search to confuse prefixes with complete words
- Using array[26] when input has non-lowercase characters — leads to index errors
- Not handling deletion properly — rare in interviews but important to understand conceptually
- Building a trie when a hash set suffices — wastes interview time on unnecessary complexity
- Forgetting to initialize the root node — a subtle bug that causes null pointer errors
Trie Practice Strategy for Interview Prep
The most effective way to learn the trie data structure is to follow a deliberate progression from simple implementation to complex application. Do not jump straight to hard problems — build your foundation first.
Start with Implement Trie (LeetCode #208). Write it once with reference material, then close your notes and rewrite it from memory. Repeat until the template is second nature. This single problem is the foundation for everything else.
Next, tackle Design Add and Search Words (#211) to learn how tries combine with DFS. The wildcard matching logic forces you to think recursively within the trie structure, which is a pattern that transfers to many other problems.
Once those feel comfortable, attempt Word Search II (#212). This hard problem combines trie construction with grid backtracking and is frequently asked at Google and Amazon. Give yourself 45 minutes before looking at hints — that mirrors real interview conditions.
Use YeetCode flashcards to reinforce the trie pattern between practice sessions. Spaced repetition helps you retain the implementation details and problem-solving intuition so that when a trie problem appears in your interview, the approach clicks immediately.
Watch Out
Don't use a Trie when a HashSet works — if you only need exact word lookups without prefix queries, a HashSet is simpler and faster. Tries add value only when prefix operations are needed.