Skip to content

Implement Trie (Prefix Tree)

Implement a Trie (also called prefix tree) with the following operations:

  • insert(word) — Insert a word into the trie.
  • search(word) — Search for an exact word in the trie and return whether it exists.
  • startsWith(prefix) — Return whether there is any word in the trie that starts with the given prefix.
OperationInputOutputNotes
Insert"apple"Tree now has path: a→p→p→l→e
Search"apple"trueComplete word exists
Search"app"falsePrefix exists but not marked as word
StartsWith"app"truePrefix exists in tree
Insert"app"Now search(“app”) returns true
  • 1 <= word.length, prefix.length <= 2000
  • word and prefix consist only of lowercase English letters.
  • At most 3 × 10^4 calls will be made to insert, search, and startsWith.
ApproachInsertSearchStartsWithSpace
RecursiveO(m)O(m)O(m)O(m × 26)
IterativeO(m)O(m)O(m)O(m × 26)

m = length of word/prefix, space = nodes × alphabet size

  • Pick Iterative for clarity and interviews — easier to explain and debug.
  • Pick Recursive if you want to practice the recursive tree traversal pattern.
Most Clear
Iterative
O(m) time · O(m×26) space
Pattern Practice
Recursive
O(m) time · O(m×26) space
★ Recommended

Build a tree of nodes where each node represents a character. For each operation, iterate through the characters, creating new nodes as needed during insertion. For search and prefix matching, follow the existing path and return whether it reaches the target or beyond.

⏱ Time O(m) Single pass per word 💾 Space O(m×26) Trie nodes storage

Insert “cat”:

Insert 'c': root → c (new node)
Insert 'a': c → a (new node)
Insert 't': a → t (new node, mark as end-of-word)

Search “cat”:

Follow 'c' → 'a' → 't' → found and marked as end-of-word → return true

Search “ca”:

Follow 'c' → 'a' → path exists but NOT marked as end-of-word → return false

StartsWith “ca”:

Follow 'c' → 'a' → path exists → return true (doesn't care about end-of-word)
class TrieNode:
children = {}
is_end_of_word = False
class Trie:
root = TrieNode()
function insert(word):
node = root
for each char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end_of_word = True
function search(word):
node = root
for each char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end_of_word
function startsWith(prefix):
node = root
for each char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True
implement_trie_iterative.py
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word: str) -> None:
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end_of_word = True
def search(self, word: str) -> bool:
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end_of_word
def startsWith(self, prefix: str) -> bool:
node = self.root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True
# Example usage
trie = Trie()
trie.insert("apple")
print(trie.search("apple")) # True
print(trie.search("app")) # False
print(trie.startsWith("app")) # True
trie.insert("app")
print(trie.search("app")) # True

Approach 2: Helper Method (Recursive Pattern)

Section titled “Approach 2: Helper Method (Recursive Pattern)”
🎯 Interview Favourite

Extract a helper method findNode(prefix) that recursively (or iteratively in the helper) searches for a node. Then search checks the end-of-word flag and startsWith only checks node existence. This reduces code duplication.

⏱ Time O(m) Single traversal 💾 Space O(m) Call stack + nodes
implement_trie_recursive.py
class TrieNode:
def __init__(self):
self.children = {}
self.is_end_of_word = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word: str) -> None:
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_end_of_word = True
def search(self, word: str) -> bool:
node = self._find_node(word)
return node is not None and node.is_end_of_word
def startsWith(self, prefix: str) -> bool:
return self._find_node(prefix) is not None
def _find_node(self, prefix: str) -> TrieNode:
node = self.root
for char in prefix:
if char not in node.children:
return None
node = node.children[char]
return node
# Example usage
trie = Trie()
trie.insert("apple")
print(trie.search("apple")) # True
print(trie.search("app")) # False
print(trie.startsWith("app")) # True
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
implement_trie_prefix_tree_space_optimized.py
"""
Solution for Implement Trie (Prefix Tree)
"""
def solve():
"""Implementation for approach 3 of Implement Trie (Prefix Tree)"""
pass
if __name__ == "__main__":
print("Solution ready")