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 string word
into the trie.boolean search(String word)
Returns true
if the string word
is in the trie (i.e., was inserted before), and false
otherwise.boolean startsWith(String prefix)
Returns true
if there is a previously inserted string word
that has the prefix prefix
, and false
otherwise.
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 <= 2000
word
and prefix
consist only of lowercase English letters.3 * 104
calls in total will be made to insert
, search
, and startsWith
.This problem requires implementing a Trie data structure. A Trie, or prefix tree, is a tree-like data structure used to efficiently store and retrieve keys in a dataset of strings. It's particularly useful for operations like autocomplete and spell-checking.
The solution involves creating a TrieNode class (implicitly or explicitly depending on the language) that represents a node in the Trie. Each node has an array (or similar structure) to store pointers to its children nodes (one for each character in the alphabet), and a boolean flag to indicate whether the node represents the end of a valid word.
The Trie
class itself contains the root node of the Trie and methods for inserting words, searching for words, and checking for prefixes.
Core Operations:
insert(word)
: This method iterates through the characters of the input word. For each character, it checks if a child node exists for that character. If not, a new node is created. The process continues until the end of the word, at which point the isEnd
flag of the final node is set to true
.
search(word)
: This method traverses the Trie based on the input word. If a node for a character is not found along the way, the word is not in the Trie, and false
is returned. If the traversal reaches the end of the word and the isEnd
flag of the final node is true
, the word is found, and true
is returned.
startsWith(prefix)
: This method is similar to search
but only needs to traverse the Trie until the end of the prefix. If it reaches the end of the prefix without encountering a missing node, it indicates that at least one word starts with that prefix, and true
is returned.
Time and Space Complexity:
Time Complexity:
insert(word)
: O(m), where m is the length of the word. This is because we iterate through each character of the word once.search(word)
: O(m), for the same reason as above.startsWith(prefix)
: O(p), where p is the length of the prefix.Space Complexity: O(N * m), where N is the number of words inserted and m is the maximum length of a word. In the worst case, each character in every word could lead to the creation of a new node.
Code Examples (Python, Java, C++, Go, TypeScript, Rust, JavaScript, C#):
The provided code examples demonstrate the implementation of the Trie data structure in various programming languages. Each example implements the Trie
class with the three required methods (insert
, search
, startsWith
). The core logic remains consistent across all languages, although the syntax and data structures used vary. The use of arrays for children (or HashMap
in Rust) allows for efficient O(1) access to child nodes based on the character. Helper functions like searchPrefix
help keep the code clean and reusable. Note that the Rust example uses Rc
and RefCell
to handle shared ownership of nodes efficiently.
Example Usage (Python):
trie = Trie()
trie.insert("apple")
print(trie.search("apple")) # Output: True
print(trie.search("app")) # Output: False
print(trie.startsWith("app")) # Output: True
trie.insert("app")
print(trie.search("app")) # Output: True
This demonstrates how to use the implemented Trie
class to insert words, search for words, and check for prefixes. Similar usage patterns apply to the other language examples.