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
.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Let's build a system to store words in a way that makes it easy to find words that start with a specific sequence of letters. A brute force approach involves checking every single existing word to see if it starts with the input sequence.
Here's how the algorithm would work step-by-step:
class BruteForceTrie:
def __init__(self):
self.word_list = []
def insert(self, word):
self.word_list.append(word)
def search_prefix(self, prefix):
matching_words = []
# Iterate through the list of stored words
for existing_word in self.word_list:
# Check if the current word starts with the given prefix
if existing_word.startswith(prefix):
matching_words.append(existing_word)
return matching_words
To efficiently store and search words, we'll create a special tree-like structure. Each level of the tree represents a character, and following a path down the tree spells out a word.
Here's how the algorithm would work step-by-step:
class Trie:
def __init__(self):
self.root_node = {}
def insert(self, word):
current_node = self.root_node
for char in word:
if char not in current_node:
# Create node if it doesn't exist
current_node[char] = {}
current_node = current_node[char]
# Mark the end of a word
current_node['#'] = True
def search(self, word):
current_node = self.root_node
for char in word:
if char not in current_node:
return False
current_node = current_node[char]
# Check if the node represents the end of a word
return '#' in current_node
def startsWith(self, prefix):
current_node = self.root_node
for char in prefix:
if char not in current_node:
return False
current_node = current_node[char]
# Prefix found if we reach here
return True
Case | How to Handle |
---|---|
Null or empty word for insert | Treat as valid and insert empty node or return immediately without inserting anything, depending on the requirements/API specification. |
Null or empty prefix for startsWith | Return true if the Trie is not empty, false otherwise, according to if the root exists. |
Null or empty word for search | Return true only if a node representing the empty word was previously inserted and marked as the end of a word. |
Inserting the same word multiple times | The Trie should correctly update the 'isEndOfWord' flag on the last character's node for each insertion, without creating duplicates. |
Searching for a prefix that is a complete word | Should return true if the prefix is a word and has been inserted. |
Inserting words with non-alphabetic characters | The solution needs to specify supported charsets and handle them accordingly (e.g., throw an exception or ignore characters if outside the supported set). |
Large number of words inserted, memory constraints | The Trie's memory usage can grow significantly with the number of words; solution should be designed to be memory-efficient, if memory limit is imposed. |
Words with extremely long length | Check for stack overflow possibility, if using recursion, and potentially use iterative approach instead. |