import collections
class TrieNode:
"""Trie 树节点类"""
def __init__(self):
# 子节点字典:键是字符,值是对应的 TrieNode 子节点
# 使用 defaultdict 可以稍微简化 addWord,但普通 dict 更清晰
self.children = {}
# 标记:从根节点到当前节点是否形成一个完整的单词
self.is_end = False
class WordDictionary:
"""实现添加和搜索单词(含通配符)的数据结构"""
def __init__(self):
"""
初始化数据结构。
"""
# 创建 Trie 树的根节点
self.root = TrieNode()
def addWord(self, word: str) -> None:
"""
将 word 添加到数据结构中,之后可以对它进行匹配。
"""
# 从根节点开始
cur = self.root
# 遍历单词中的每个字符
for char in word:
# 如果字符对应的子节点不存在...
if char not in cur.children:
# ...则创建一个新的 TrieNode 作为子节点
cur.children[char] = TrieNode()
# 移动到子节点
cur = cur.children[char]
# 单词遍历结束后,将当前节点的 is_end 标记设为 True
# 表示从根到此节点是一个完整的单词
cur.is_end = True
def search(self, word: str) -> bool:
"""
搜索 word 是否在数据结构中。
word 可能包含 '.',每个 '.' 可以匹配任意一个字母。
返回 True 如果 word 在结构中匹配成功,否则返回 False。
"""
# 定义内部的 DFS 辅助函数
# node: 当前遍历到的 Trie 节点
# index: 当前正在匹配 word 中的字符索引
def dfs_help(node: TrieNode, index: int) -> bool:
# --- 递归基准情况 (Base Case) ---
# 如果 index 到达了 word 的末尾
if index == len(word):
# 只有当当前 Trie 节点标记为单词结尾时,才算真正匹配成功
return node.is_end
# --- 递归步骤 (Recursive Step) ---
# 获取当前需要匹配的字符
char = word[index]
# 情况 1: 当前字符是通配符 '.'
if char == '.':
# 需要尝试当前节点的所有子路径
# 如果 children 为空,则循环不会执行,直接返回 False (见循环后的 return)
for child_node in node.children.values():
# 对每个子节点,递归调用 dfs_help 尝试匹配 word 的剩余部分 (index + 1)
# 只要有任意一个子路径能够成功匹配,整个 search 就成功了
if dfs_help(child_node, index + 1):
return True
# 如果遍历完所有子节点都没有找到成功的路径,则说明此路不通
return False
# 情况 2: 当前字符是普通字母
else:
# 检查该字母是否存在于当前节点的子节点中
if char in node.children:
# 如果存在,则沿着该字母对应的子节点继续向下递归搜索
return dfs_help(node.children[char], index + 1)
else:
# 如果该字母对应的子节点不存在,说明无法匹配,返回 False
return False
# --- search 方法的主调用 ---
# 从 Trie 树的根节点 (self.root) 和单词的起始索引 (0) 开始执行 DFS
return dfs_help(self.root, 0)
# 示例用法:
# obj = WordDictionary()
# obj.addWord("bad")
# obj.addWord("dad")
# obj.addWord("mad")
# print(obj.search("pad")) # 输出: False
# print(obj.search("bad")) # 输出: True
# print(obj.search(".ad")) # 输出: True
# print(obj.search("b..")) # 输出: True
# Your WordDictionary object will be instantiated and called as such:
# obj = WordDictionary()
# obj.addWord(word)
# param_2 = obj.search(word)