Code Templates
Trie
Use Cases for Trie Data Structures
Use Case | Description | Example |
---|---|---|
Autocomplete Suggestions | Provide real-time suggestions as users type in a search box. | Typing "app" in a search bar could suggest "apple," "application," and "appetizer." |
Prefix Matching | Efficiently find all words in a dataset that start with a given prefix. | Given the prefix "pre," the Trie can return "prefix," "predecessor," and "presentation." |
Data Compression | Implement algorithms like Lempel-Ziv (used in formats like ZIP) to store repeated patterns. | Use a Trie to store patterns of strings for efficient compression. |
Code Template
Class initializing
- Initializes an empty dictionary to hold child nodes for each character.
- Sets a boolean flag to indicate if this node marks the end of a valid word.
Insert a new word
- Starts at the root and iterates through each character in the word.
- If a character is not already a child, it creates a new
TrieNode
for that character.
Internal search
- Implement an internal method checks if a given prefix exists in the Trie.
Search by prefix or word
- Use
_search_prefix
function to check if givenprefix
orword
exists in the Trie.
class TrieNode:def __init__(self):self.children = {}self.is_end = Falseclass Trie:def __init__(self):self.root = TrieNode()
Common mistakes
- Wrong Node Structure Implementation
# Wrong: incorrect children initializationclass TrieNode:def __init__(self):self.children = [] # Should be dictionaryself.is_end = False# Wrong: missing end markerclass TrieNode:def __init__(self):self.children = {} # Missing is_end flag# Correct:class TrieNode:def __init__(self):self.children = {}self.is_end = False
- Wrong Insert Implementation
# Wrong: not updating node referencedef insert(self, word):node = self.rootfor char in word:if char not in self.root.children: # Using root instead of current nodeself.root.children[char] = TrieNode()# Wrong: forgetting end markerdef insert(self, word):node = self.rootfor char in word:if char not in node.children:node.children[char] = TrieNode()node = node.children[char]# Missing node.is_end = True# Correct:def insert(self, word):node = self.rootfor char in word:if char not in node.children:node.children[char] = TrieNode()node = node.children[char]node.is_end = True
- Wrong Search Implementation
# Wrong: incorrect return conditiondef search(self, word):node = self._search_prefix(word)return node # Should check is_end# Wrong: not handling None returndef search(self, word):node = self._search_prefix(word)return node.is_end # Could raise AttributeError# Correct:def search(self, word):node = self._search_prefix(word)return node and node.is_end
Issues and consideration
- Concurrency: The current implementation is not thread-safe, which can lead to issues if multiple threads modify the Trie simultaneously. Implement locking mechanisms or use concurrent data structures if the Trie will be accessed or modified in a multi-threaded environment.
- Balancing Trade-offs: The choice between a standard Trie and more advanced structures (like a suffix tree or a compressed Trie) can affect performance and complexity. Analyze the specific requirements of your application (e.g., search speed, memory efficiency) to choose the most appropriate data structure.
Related Problem
208. Implement Trie (Prefix Tree)
class TrieNode:def __init__(self):self.children = {}self.is_end = Falseclass Trie:def __init__(self):self.root = TrieNode()def insert(self, word):node = self.rootfor char in word:if char not in node.children:node.children[char] = TrieNode()node = node.children[char]node.is_end = Truedef _search_prefix(self, prefix):node = self.rootfor char in prefix:if char not in node.children:return Falsenode = node.children[char]return nodedef startsWith(self, prefix):return bool(self._search_prefix(prefix))def search(self, word):node = self._search_prefix(word)return node and node.is_end
class TrieNode:def __init__(self):self.children = {}self.is_end = Falseclass Trie:def __init__(self):self.root = TrieNode()def insert(self, word):node = self.rootfor char in word:if char not in node.children:node.children[char] = TrieNode()node = node.children[char]node.is_end = Truedef _search_prefix(self, prefix):node = self.rootfor char in prefix:if char not in node.children:return Falsenode = node.children[char]return nodedef startsWith(self, prefix):return bool(self._search_prefix(prefix))def search(self, word):node = self._search_prefix(word)return node and node.is_endclass Solution:def findWords(self, board, words):# Initialize the Trie and insert all wordstrie = Trie()for word in words:trie.insert(word)m, n = len(board), len(board[0])result = set()visited = [[False] * n for _ in range(m)]def backtrack(x, y, node, path):if node.is_end: # If we reached the end of a wordresult.add(path) # Add the word to the resultnode.is_end = False # Avoid adding the same word again# Explore the adjacent cellsfor dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: # Up, Down, Left, Rightnx, ny = x + dx, y + dyif 0 <= nx < m and 0 <= ny < n and not visited[nx][ny]:char = board[nx][ny]if char in node.children: # If the character is in the Trievisited[nx][ny] = True # Mark the cell as visitedbacktrack(nx, ny, node.children[char], path + char) # Recur for the next cellvisited[nx][ny] = False # Backtrack: unmark the cellfor i in range(m):for j in range(n):char = board[i][j]if char in trie.root.children: # Start backtracking if the character is in the Trievisited[i][j] = True # Mark the cell as visitedbacktrack(i, j, trie.root.children[char], char) # Start backtrackingvisited[i][j] = False # Backtrack: unmark the cellreturn list(result) # Convert the result set to a list