Trie
Introduction to Trie
A trie, or a prefix tree, is a type of search tree that is usually used to store strings. Some of the properties of Trie are:
➡️ Each path from the root to leaves forms a word.
➡️ Each node except for the root node contains a value.
➡️ All the descendants of a node share a common prefix associated to that node. For example,
➡️ Each path from the root to leaves forms a word.
➡️ Each node except for the root node contains a value.
➡️ All the descendants of a node share a common prefix associated to that node. For example,
are
and art
share ar
as the prefix.➡️ Trie Operations: inserting a new string, and searching for a given string.
Implementation of Trie
General Function Calls around Trie
Implement a trie with insert, search, and startsWith methods.
Example:
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // returns true
trie.search("app"); // returns false
trie.startsWith("app"); // returns true
trie.insert("app");
trie.search("app"); // returns true
Note:
You may assume that all inputs are consist of lowercase letters a-z.
All inputs are guaranteed to be non-empty strings.
Implementation of Trie - Java
Define TrieNode
Class TrieNode:
➡️ A boolean variable isWord to indicate whether we can form a word or it's only a prefix.
➡️ An array of TrieNode named children to store its children node.
➡️ A constructor which initializes isWord to false, and children array of 26 letters(lowercase) will be used.
class TrieNode { TrieNode[] children; boolean isEndOfWord; public TrieNode() { children = new TrieNode[26]; isEndOfWord = false; }}
Insertion into Trie
Given a new string word, we would iterate through it. Starting from the dummy node root and the first character c, we would check whether c is in root.children:
➡️ if it is, we can move to that node and increment to next character as well;
➡️ if not, we need to initiate a new node so that we can attach c to the trie.
public void insert(String word) {
TrieNode node = root;
for (int i = 0; i < word.length(); i++) {
int index = word.charAt(i) - 'a';
if (node.children[index] == null) {
node.children[index] = new TrieNode();
}
node = node.children[index];
}
node.isEndOfWord = true;
}
//Time Complexity: O(L) where L is the length of the word.
Searching in Trie
Similarly to insert, we also start the iteration with the first character and the dummy node. If we do not find the character in its children, we can return false. Remember to check isWord after reaching the end of word.
public boolean search(String word) {
TrieNode current_node = root;
for (int i = 0; i < word.length(); i++) {
int index = word.charAt(i) - 'a';
if (current_node.children[index] == null) return false;
current_node = current_node.children[index];
}
return current_node.isWord;
}
//Time Complexity: O(L) where L is the length of the word.
StartsWith in Trie
The only different to search is that, we do not need to check isWord at the end.
public boolean startsWith(String prefix) {
TrieNode current_node = root;
for (int i = 0; i < prefix.length(); i++) {
int index = prefix.charAt(i) - 'a';
if (current_node.children[index] == null) return false;
current_node = current_node.children[index];
}
return true;
}
//Time Complexity: O(L) where L is the length of the prefix.