Solving Leetcode Interviews in Seconds with AI: Design Add and Search Words Data Structure
Introduction
In this blog post, we will explore how to solve the LeetCode problem "211" using AI. LeetCode is a popular platform for preparing for coding interviews, and with the help of AI tools like Chatmagic, we can generate solutions quickly and efficiently - helping you pass the interviews and get the job offer without having to study for months.
Problem Statement
Design a data structure that supports adding new words and finding if a string matches any previously added string. Implement the WordDictionary class: WordDictionary() Initializes the object. void addWord(word) Adds word to the data structure, it can be matched later. bool search(word) Returns true if there is any string in the data structure that matches word or false otherwise. word may contain dots '.' where dots can be matched with any letter. Example: Input ["WordDictionary","addWord","addWord","addWord","search","search","search","search"] [[],["bad"],["dad"],["mad"],["pad"],["bad"],[".ad"],["b.."]] Output [null,null,null,null,false,true,true,true] Explanation WordDictionary wordDictionary = new WordDictionary(); wordDictionary.addWord("bad"); wordDictionary.addWord("dad"); wordDictionary.addWord("mad"); wordDictionary.search("pad"); // return False wordDictionary.search("bad"); // return True wordDictionary.search(".ad"); // return True wordDictionary.search("b.."); // return True Constraints: 1 <= word.length <= 25 word in addWord consists of lowercase English letters. word in search consist of '.' or lowercase English letters. There will be at most 2 dots in word for search queries. At most 104 calls will be made to addWord and search.
Explanation
- Trie with Length Grouping: Store words in a Trie data structure, but also group words by their lengths in a dictionary. This allows for faster searching by first checking if any words of the same length exist before traversing the Trie.
- Depth-First Search (DFS) for '.' Handling: When encountering a '.' during the search, explore all possible branches in the Trie at that level using a recursive DFS approach.
- Optimization: Using dictionaries by length significantly cuts down search time as it avoids unnecessary Trie traversals for words of different lengths.
- Runtime Complexity:
addWord: O(m),search: O(m) on average (m is the length of the word), but can be O(26^k m) in the worst case where k is the number of dots. Storage Complexity: O(Nm), N is the number of words.
Code
class TrieNode:
def __init__(self):
self.children = {}
self.is_word = False
class WordDictionary:
def __init__(self):
self.trie = TrieNode()
self.words_by_length = {}
def addWord(self, word: str) -> None:
if len(word) not in self.words_by_length:
self.words_by_length[len(word)] = []
self.words_by_length[len(word)].append(word)
node = self.trie
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.is_word = True
def search(self, word: str) -> bool:
if len(word) not in self.words_by_length:
return False
def dfs(node, i):
if i == len(word):
return node.is_word
char = word[i]
if char == '.':
for child in node.children.values():
if dfs(child, i + 1):
return True
return False
else:
if char not in node.children:
return False
return dfs(node.children[char], i + 1)
return dfs(self.trie, 0)