Implement Trie Methods
DESCRIPTION
Implement the search and delete methods of a Trie.
- search(word) returns true if the word is in the Trie, and false otherwise.
- delete(word) removes the word from the Trie, and does not return a value.
The creation of the Trie and the insert method are already implemented for you.
The test cases include two parameters:
- initialWords: a list of words to add to the Trie,
- commands: a list of commands to run. Each command is a tuple, where the first element is either "search" or "delete", and the second element is the word to search or delete.
The test cases will create the Trie with the initial words, and then run the commands in order, and compare the output to the expected output. Note we only compare the output of the search commands, not the delete commands.
EXAMPLES
Input:
initialWords = ["apple", "app", "apartment"] commands = [ ["search", "apple"], ["search", "apartment"], ["search", "appl"], ["delete", "app"], ["search", "app"], ]
Output: [True, True, False, False]
Explanation:
Trie.search("apple") -> True Trie.search("apartment") -> True Trie.search("appl") -> False Trie.delete("app") -> None # Return value not checked Trie.search("app") -> False
Run your code to see results here
Explanation
Search
The intiution for searching is to search for each character in the word by traversing down nodes in the trie. When we reach the end of the word, we check if that node is marked as the end of a word. This is necessary
def search(self, word):"""Search the trie for the given word.Returns True if the word exists in the trie, False otherwise"""# start from the root nodenode = self.root# traverse down the triefor char in word:if char not in node.children:# the word does not exist in the triereturn Falsenode = node.children[char]return node.is_end_of_word
Delete
Intuition
To delete a word from a trie, we need to first unmark the node corresponding to the last character of the word as the end of a word.
The Trie below contains BAT and BATH. To delete BAT, we need to unmark T as the end of a word.
Then, we need to delete all nodes from that word that are not part of any other words in the trie.
For example, the Trie below contains two words: "BALLET" and "BALLOON". If we were to delete "BALLET", we can safely delete "E" and "T", but not "BALL" because it is part of "BALLOON".
If we look closer at the nodes we can delete, they have two properties in common:
- They are not the end of any word
- They don't have any children
So we want to first traverse down to the node corresponding to the last character of the word we are trying to delete and unmark it as the end of a word. From there, we can traverse back "up" by deleting nodes that are not part of any other words based on the two conditions above.
Implementation
The above logic is best implemented recursively with a helper function _delete. Each call to _delete returns a boolean indicating whether the current node can be deleted from its' parent's dictionary of children.
It returns True if:
- The current node is not the end of any word (not node.isEndOfWord) AND
- The current node has no children (len(node.children) == 0)
Base Case The base case for the recursive function is when we reach the end of the word. We need to set node.isEndOfWord = False to ensure that we removed the given word from the trie.
At this point, we can start deleting nodes that are not part of any other words. Each node returns True if it should be deleted from its parent's dictionary of children based on the two conditions above.
The parent receives that boolean and:
- If the boolean is True, it deletes the child node from its dictionary of children. The parent node then returns if it should be deleted as well.
- If the boolean is False, it does not delete the child node and returns False, which prevents any further deletions.
def delete(self, word):"""Deletes the given the word from the Trie.Returns None."""def _delete(node, index):# base case: We have reached the end of the wordif index == len(word):if not node.isEndOfWord:return Falsenode.isEndOfWord = Falsereturn len(node.children) == 0char = word[index]if char not in node.children:return Falsedelete_child = _delete(node.children[char], index + 1)if delete_child:del node.children[char]return not node.isEndOfWord and len(node.children) == 0return Falseif _delete(self.root, 0):if word and word[0] in self.root.children:# delete first character from the root's childrendel self.root.children[word[0]]
Loading comments...