- JY:Trie 树升级版(查找单词时支持
"."
的模糊匹配查找)
![](https://img-blog.csdnimg.cn/img_convert/23b8efd061941ed3cf49e9f54dda4ea2.png)
![](https://img-blog.csdnimg.cn/img_convert/fa2d12d7021c61683663ba82e1160f09.png)
![](https://img-blog.csdnimg.cn/img_convert/ea3f95d2b615d428bc5f4176b1d940c1.png)
1、Trie 基础版(基于字典实现)
class TrieNode:
def __init__(self):
self.end_of_word = False
self.children = {}
class WordDictionary:
def __init__(self):
# jy: 初始化 Trie 树的根节点
self.root = TrieNode()
def addWord(self, word: str) -> None:
"""
往 Trie 树中添加 word
"""
current = self.root
for c in word:
if c not in current.children:
current.children[c] = TrieNode()
current = current.children[c]
current.end_of_word = True
def search(self, word: str) -> bool:
"""
从 Trie 树的根节点搜索单词 word (支持 "." 模糊匹配任一字符)
"""
# jy: 递归函数中支持传入两个参数, 从哪个节点位置开始查找
return self._search(word, self.root)
def _search(self, word, node):
"""
从 Trie 树的 node 节点开始搜索 word (支持 "." 模糊匹配任一字符)
"""
current = node
# jy: 由于后续可能需要跳过当前字符 c, 因此需要知道当前字符在 word
# 中的下标位置 i, 随后可通过下标 i+1 开始表示跳过当前字符
for i, c in enumerate(word):
# jy: 深度优先搜索: 如果当前搜索字符为 "." (表示可以匹配任一字符), 则跳过当前
# 字符 (即 key 值), 从下一个字符 (对应的节点即 current_child) 开始搜索
if c == '.':
for key, current_child in current.children.items():
if self._search(word[i+1:], current_child):
return True
return False
# jy: 如果搜索字符不为 ".", 且不在当前节点的子节点中, 则返回 False;
# 注意: 必须先确保字符 c 不为 "." 后才进行当前判断, 否则直接进行
# 当前判断时, 如果碰到的的字符 "." 会直接返回 False, 不符合预期
elif c not in current.children:
return False
# jy: current 更新为当前节点的下一节点, 进行下一轮循环, 判断下
# 一个搜索字符是否在 Trie 树的下一相邻层子节点中
current = current.children[c]
# jy: 经过以上 for 循环后, current 为 word 最后一个字符对应的 TrieNode,
# 如果其 end_of_word 属性为 Ture, 表明该单词存在
return current.end_of_word
wordDictionary = WordDictionary()
wordDictionary.addWord("bad")
wordDictionary.addWord("dad")
wordDictionary.addWord("mad")
print(wordDictionary.search("pad")) # return False
print(wordDictionary.search("bad")) # return True
print(wordDictionary.search(".ad")) # return True
print(wordDictionary.search("b..")) # return True
2、双字典
class WordDictionary:
def __init__(self):
# jy: 记录单词以及单词的长度
self.word_len = {}
# jy: 记录指定长度的单词列表
self.len_words = defaultdict(list)
def addWord(self, word: str) -> None:
# jy: 如果单词 word 已经存在于 self.word_len 字典中, 表明
# 之前已经添加过, 不需要重复添加; 否则基于单词长度添加到
# self.len_words 和 self.word_len 中
if word not in self.word_len:
len_ = len(word)
self.len_words[len_].append(word)
self.word_len[word] = len_
def search(self, word: str) -> bool:
# jy: 如果单词在 self.word_len 字典中, 直接返回 True
if word in self.word_len:
return True
# jy: 只有当 word 中含 "." 时, 当前单词 w 才可能与 word 匹配
# (否则不可能匹配, 因为 word 不在 self.word_len 中)
if "." not in word:
return False
# jy: 从与 word 长度相同的候选列表中查找
for w in self.len_words[len(word)]:
# jy: length 从左到右记录 w 与 word 能相互匹配的字符个数
length = 0
for i in range(len(w)):
if w[i] == word[i] or word[i] == '.':
length += 1
else:
break
if length == len(w):
return True
return False
wordDictionary = WordDictionary()
wordDictionary.addWord("bad")
wordDictionary.addWord("dad")
wordDictionary.addWord("mad")
print(wordDictionary.search("pad")) # return False
print(wordDictionary.search("bad")) # return True
print(wordDictionary.search(".ad")) # return True
print(wordDictionary.search("b..")) # return True