Taro Logo

Implement Magic Dictionary

Medium
Google logo
Google
Topics:
Strings

Design a data structure that is initialized with a list of different words. Given a string, determine if you can change exactly one character in this string to match any word in the data structure.

Implement the MagicDictionary class:

  • MagicDictionary() Initializes the object.
  • void buildDict(String[] dictionary) Sets the data structure with an array of distinct strings dictionary.
  • bool search(String searchWord) Returns true if you can change exactly one character in searchWord to match any string in the data structure; otherwise, returns false.

Example:

Input:
["MagicDictionary", "buildDict", "search", "search", "search", "search"]
[[], [["hello", "leetcode"]], ["hello"], ["hhllo"], ["hell"], ["leetcoded"]]
Output:
[null, null, false, true, false, false]

Explanation:
MagicDictionary magicDictionary = new MagicDictionary();
magicDictionary.buildDict(["hello", "leetcode"]);
magicDictionary.search("hello"); // return False
magicDictionary.search("hhllo"); // We can change the second 'h' to 'e' to match "hello" so we return True
magicDictionary.search("hell"); // return False
magicDictionary.search("leetcoded"); // return False

Solution


Naive Solution

The naive solution involves iterating through the dictionary for each search word and comparing each word in the dictionary with the search word. For each comparison, we count the number of differing characters. If exactly one character differs, we return true. Otherwise, we continue the search. If we reach the end of the dictionary without finding a match, we return false.

Code (Python)

class MagicDictionary:
    def __init__(self):
        self.dictionary = []

    def buildDict(self, dictionary: List[str]) -> None:
        self.dictionary = dictionary

    def search(self, searchWord: str) -> bool:
        for word in self.dictionary:
            if len(word) == len(searchWord):
                diff_count = 0
                for i in range(len(word)):
                    if word[i] != searchWord[i]:
                        diff_count += 1
                if diff_count == 1:
                    return True
        return False

Time Complexity

  • buildDict: O(N), where N is the number of words in the input dictionary.
  • search: O(M * L), where M is the number of words in the dictionary and L is the length of the search word.

Space Complexity

  • O(N), where N is the number of words in the dictionary, to store the dictionary.

Optimal Solution

A slightly more optimal solution could involve using a hash map to store words grouped by their length. During the search, only words with the same length as the searchWord need to be considered. This approach reduces the number of unnecessary comparisons.

Code (Python)

class MagicDictionary:
    def __init__(self):
        self.length_map = {}

    def buildDict(self, dictionary: List[str]) -> None:
        for word in dictionary:
            length = len(word)
            if length not in self.length_map:
                self.length_map[length] = []
            self.length_map[length].append(word)

    def search(self, searchWord: str) -> bool:
        length = len(searchWord)
        if length not in self.length_map:
            return False

        for word in self.length_map[length]:
            diff_count = 0
            for i in range(length):
                if word[i] != searchWord[i]:
                    diff_count += 1
            if diff_count == 1:
                return True
        return False

Time Complexity

  • buildDict: O(N), where N is the number of words in the input dictionary.
  • search: O(K * L), where K is the number of words with the same length as the search word, and L is the length of the search word. In the worst case, K can be equal to N, so it can still be O(N*L), but on average it's better if the word lengths are varied.

Space Complexity

  • O(N), where N is the number of words in the dictionary, to store the length_map.

Edge Cases

  1. Empty dictionary.
  2. Empty search word (though constraints specify length >= 1).
  3. No words in the dictionary with the same length as the search word.

These edge cases are handled correctly in the provided implementations.