Implement Trie (Prefix Tree)
Each node has 26 child slots, one per letter, and an isEnd flag. Insert walks down from the root, creating missing nodes, and sets isEnd on the last node. Search and startsWith walk the same path but never create anything. The path answers the prefix question, and only the isEnd flag answers the exact-word question.
A node exists for a prefix exactly when some stored word starts with that prefix, and isEnd is true exactly when that prefix is itself a stored word.
Problem
Build a Trie class. It stores words and answers two questions about them:
search(word)istrueonly if this exact word was stored.startsWith(prefix)istrueif at least one stored word begins withprefix.
A shorter piece of a stored word is a prefix, not a word. After apple is stored, search("app") is false, but startsWith("app") is true.
Trie() makes an empty trie, and insert(word) stores a word.
The calls in order: Trie() first, then any mix of insert, search and startsWith. Every word and prefix uses only lowercase letters a to z.
For each search and startsWith, true or false. Trie() and insert return nothing (shown as null below).
After apple is stored, apple is found, but app is not: it is only a prefix. startsWith("app") is true because apple starts with app. Once app is inserted as a word, search("app") is true.
cat starts with ca, so startsWith("ca") is true. But ca was never stored as a word, and dog was never stored at all.
- • 1 ≤ word.length, prefix.length ≤ 2000
- • word and prefix use only lowercase letters a to z
- • At most 3 · 10^4 calls in total to insert, search and startsWith
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.
- 1.
If I store
appleas one whole string, how would I checkapp? Could I reuse anything I did forapple? - 2.
Words that start with the same letters, like
appandapple, could share their first letters. What would that look like as a tree? - 3.
What does one node need to hold? Think about the letters that can come next, and whether a word stops right there.
- 4.
search("app")andstartsWith("app")walk the same letters. What is the one difference in their answers? - 5.
When a letter has no node during a search, what can I say about the answer? What changes during an insert?
Brute force approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Store words in a vector; search and startsWith check every stored word | O(N · L) | O(T) |
| Optimal | One node per letter, children by letter, and a flag where a word ends | O(L) | O(26 · T) |
Why does this belong to this pattern?
- “many words”Words share their first letters, so store each letter once as a node and let words share the top of the tree.
- “prefix”A prefix is just a path from the root, so checking it is a walk down the tree with no scanning.
- “exact word vs prefix”Two questions on the same path. The path answers the prefix question, and one flag per node answers the word question.
This is the anchor of the Trie pattern. A prefix question is a walk, and the walk either finishes or falls off. The path tells you about prefixes, and the isEnd flag tells you about whole words. Because apple and app share their first three nodes, each shared letter is stored and checked once. Later trie questions build on this: Replace Words stops at the first end flag it meets, and Search Suggestions keeps a short list at each node.
Don't make this mistake
Insert apple, then call search with app. The walk reaches the second p, so the wrong version returns true. The right answer is false, because app was never inserted as a word. Only the isEnd flag says a word stops there.
Insert apple, then call startsWith with app. The path exists, so the answer is true. The wrong version checks isEnd, gets false, and says no stored word starts with app, which is wrong. A prefix does not need to be a word.
Insert apple, then search apply. The walk goes a, p, p, l, then y has no node, so cur becomes nullptr. The last line reads cur->isEnd on nothing, and the program crashes. Stop as soon as a letter is missing.
Insert apple, then insert app. The wrong version replaces the first a node, and with it the whole p, p, l, e branch. Then search apple returns false, even though it was inserted. Only create a node when its slot is empty.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like Trie translate into production architectures and low-level memory mechanics.