A stored-prefix query contains a symbol matching any one character.
Keep true
match(index,node) is true exactly when a terminal descendant matches the remaining suffix.
Reuse it
Branch recursion only at ambiguous symbols and preserve terminal semantics at exact query length.
Read it this way: bat, dad, and mad share root but have separate first-letter branches. Step through the frames to watch the state change. The last frame shows the answer or the stopping condition.
Pattern: Trie plus DFS when a wildcard appears.
Simple idea: Normal letters follow one child. A dot tries every child. The end marker
still checks that the full word length matched.
class WordDictionary: def __init__(self) -> None: self.root: dict = {} def add_word(self, word: str) -> None: node = self.root for char in word: node = node.setdefault(char, {}) node[None] = True def search(self, word: str) -> bool: def match(index: int, node: dict) -> bool: if index == len(word): return None in node if word[index] == ".": return any(match(index + 1, child) for key, child in node.items() if key) return word[index] in node and match(index + 1, node[word[index]]) return match(0, self.root)
Cost: Adding takes O(L) time. A normal search takes O(L). Many wildcards can make
search exponential in the word length.