Design Add And Search Words Data Structure

To solve this coding challenge, we need to design a data structure that supports the addition of new words and allows searching for words with the possibility of using '.' as a wildcard character. The most effective way to implement this is by using a Trie (prefix tree) data structure, which allows for efficient storing and searching of the strings.

Explanation

WordDictionary Class

We will create a
WordDictionary
class with the following functionalities:
  1. Initialization : Initialize an empty Trie.
  2. addWord() : Add a word to the Trie.
  3. search() : Search for a word in the Trie where '.' can match any character.
  4. Detailed Trie Structure
    A Trie is a tree-like data structure that stores a dynamic set of strings, where the keys are usually strings. Each node represents a single character of the string.
    Adding a Word
  5. Start from the root.
  6. For every character in the word, move to the corresponding child node. If it does not exist, create a new node.
  7. Mark the end of the word.
  8. Searching a Word
  9. Similar to adding a word but needs to handle the '.' wildcard.
  10. If the current character is '.', recursively search all children nodes.
  11. If the current character is a regular character, move to the corresponding child.
  12. At the end of the search, check if the current node marks the end of a word.
  13. Example
    Given inputs like:
                                                
    ["WordDictionary", "addWord", "addWord", "addWord", "search", "search", "search", "search"]
    [[], ["bad"], ["dad"], ["mad"], ["pad"], ["bad"], [".ad"], ["b.."]]
    
                                            
    The output should be:
                                                
    [null, null, null, null, false, true, true, true]
    
                                            

    Step-by-Step Explanation

  14. Initialization :
    • Create an empty root node which is an empty dictionary.
  15. Adding a Word :
    • Traverse each character of the word.
    • If the character is not in the current node, create a new dictionary for that character.
    • Move to the next node.
    • After inserting all characters, mark the end of the word by setting a special marker (e.g., '$').
  16. Searching a Word :
    • Traverse each character of the word.
    • If the current character is '.', recursively call the search function on all child nodes.
    • If it's a regular character, move to that child node.
    • If none of the child nodes lead to a successful search, return false.
    • At the end, check if the current node is marked as the end of a word.

Detailed Steps in Pseudocode

Here, we illustrate the pseudocode in stages, adding comments to explain each part:
                                            
# Define the WordDictionary class
class WordDictionary:

    # Initialization method
    def __init__():
        # Initialize the root of the Trie as an empty dictionary
        root = {}

    # Method to add a word to the Trie
    def addWord(word):
        # Start from the root node
        node = root
        # Traverse each character in the word
        for character in word:
            # If the character is not yet in the current node, add it
            if character not in node:
                node[character] = {}
            # Move to the next node
            node = node[character]
        # Mark the end of the word with a special symbol, e.g., '$'
        node['$'] = True

    # Method to search for a word in the Trie
    def search(word):
        # Helper recursive function to perform search
        def search_in_node(word, node):
            # Traverse each character with its index
            for index, character in enumerate(word):
                # If character is '.' search all child nodes
                if character == '.':
                    # Recursively search all possible branches in the subsequent characters
                    for child in node:
                        # Ensure we don't match the special end marker
                        if child != '$' and search_in_node(word[index + 1:], node[child]):
                            return True
                    # If none matched, return false
                    return False
                else:
                    # If character is missing, return false
                    if character not in node:
                        return False
                    # Move to the next node
                    node = node[character]
            # Return true if the end of the word is reached,
            # indicated by presence of special end marker
            return '$' in node
        
        # Call the helper function starting from the root
        return search_in_node(word, root)

                                        
In the pseudocode above, you see that each function and its steps are clearly labeled. Make sure to understand each step and how they relate to the problem-solving process.