Implement Trie (Prefix Tree)
MedPrompt
A trie (pronounced as "try") or prefix tree is a tree data structure used to efficiently store and retrieve keys in a dataset of strings. There are various applications of this data structure, such as autocomplete and spellchecker.
Implement the Trie class:
Trie()Initializes the trie object.void insert(String word)Inserts the stringwordinto the trie.boolean search(String word)Returnstrueif the stringwordis in the trie (i.e., was inserted before), andfalseotherwise.boolean startsWith(String prefix)Returnstrueif there is a previously inserted stringwordthat has the prefixprefix, andfalseotherwise.
Example 1:
Input
["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
Output
[null, null, true, false, true, null, true]
Explanation
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // return True
trie.search("app"); // return False
trie.startsWith("app"); // return True
trie.insert("app");
trie.search("app"); // return True
Constraints:
1 <= word.length, prefix.length <= 2000wordandprefixconsist only of lowercase English letters.- At most
3 * 104calls in total will be made toinsert,search, andstartsWith.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach uses a simple array to store characters and implements a basic trie structure. Each node in the trie contains a boolean flag to mark the end of a word and an array of size 26 (for lowercase English letters) to store child nodes.
Algorithm
- Create a TrieNode class with an array of size 26 for children and a boolean flag
- For insert:
- Start from root
- For each character, create a new node if it doesn't exist
- Mark the last node as end of word
- For search:
- Traverse the trie following the characters
- Return true if last node exists and is marked as end of word
- For startsWith:
- Similar to search but only check if path exists
Walkthrough
In this approach, we create a TrieNode class that contains:
- A boolean flag
isEndOfWordto mark if the node represents the end of a word - An array of TrieNode references of size 26 for each possible lowercase letter
Here's the implementation:
class TrieNode { TrieNode[] children; boolean isEndOfWord; public TrieNode() { children = new TrieNode[26]; isEndOfWord = false; }} class Trie { private TrieNode root; public Trie() { root = new TrieNode(); } public void insert(String word) { TrieNode current = root; for(char ch : word.toCharArray()) { int index = ch - 'a'; if(current.children[index] == null) { current.children[index] = new TrieNode(); } current = current.children[index]; } current.isEndOfWord = true; } public boolean search(String word) { TrieNode node = searchNode(word); return node != null && node.isEndOfWord; } public boolean startsWith(String prefix) { return searchNode(prefix) != null; } private TrieNode searchNode(String str) { TrieNode current = root; for(char ch : str.toCharArray()) { int index = ch - 'a'; if(current.children[index] == null) { return null; } current = current.children[index]; } return current; }}Complexity
Time
O(m) for all operations, where m is the length of the word/prefix
Space
O(N * 26 * M) where N is the number of words and M is average word length. Each node contains an array of size 26.
Trade-offs
Pros
Simple implementation with array indexing
Constant time lookup for children (array access)
Memory efficient for small alphabets
Cons
Fixed size array wastes space for sparse nodes
Not flexible for different character sets
Memory intensive for large character sets
Solutions
Solution
public class Trie { bool isEnd ; Trie [] children = new Trie [ 26 ]; public Trie () { } public void Insert ( string word ) { Trie node = this ; foreach ( var c in word ) { var idx = c - 'a' ; node . children [ idx ] ??= new Trie (); node = node . children [ idx ]; } node . isEnd = true ; } public bool Search ( string word ) { Trie node = SearchPrefix ( word ); return node != null && node . isEnd ; } public bool StartsWith ( string prefix ) { Trie node = SearchPrefix ( prefix ); return node != null ; } private Trie SearchPrefix ( string s ) { Trie node = this ; foreach ( var c in s ) { var idx = c - 'a' ; if ( node . children [ idx ] == null ) { return null ; } node = node . children [ idx ]; } return node ; } } /** * Your Trie object will be instantiated and called as such: * Trie obj = new Trie(); * obj.Insert(word); * bool param_2 = obj.Search(word); * bool param_3 = obj.StartsWith(prefix); */Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.