Search
⌘K
Trie

Implement Trie Methods

medium

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.

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
Do not modify any parts of the code other than the functions labled with "=== YOUR CODE HERE ===".

Explanation

It will help to refresh your memory on how to visualize each operation before diving into the implementation.
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
Solution
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 node
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.is_end

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.
HTABHTAB
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".
TENOOLLAB
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.
Solution
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 word
if index == len(word):
# Mark the node as not being the end of a word
node.is_end = False
# Return True if the node should be deleted
return len(node.children) == 0
char = word[index]
child = node.children.get(char)
if child is None:
return False # Word not found
should_delete_child = _delete(child, index + 1)
if should_delete_child:
del node.children[char]
# Return True if current node should be deleted
return not node.is_end and len(node.children) == 0
_delete(self.root, 0)

Your account is free and you can post anonymously if you choose.

Unlock Premium Coding Content

Interactive algorithm visualizations
Reading Progress

On This Page