为了提高我的单词查找的速度,我拜读了@Rshcaroline的代码,发现trie树是一个很好解决这个问题的方法
Trie树,又叫字典树、前缀树(Prefix Tree)、单词查找树 或 键树,是一种多叉树结构
Trie树的基本性质:
- 根节点不包含字符,除根节点外的每一个子节点都包含一个字符。
- 从根节点到某一个节点,路径上经过的字符连接起来,为该节点对应的字符串。
- 每个节点的所有子节点包含的字符互不相同。
通常在实现的时候,会在节点结构中设置一个标志,用来标记该结点处是否构成一个单词(关键字)。
为了了解它的实现,我从leetcode中找了题目Implement Trie (Prefix Tree)做了一下
一下是我的代码
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = {}
self.END = "$"
def insert(self, word):
"""
Inserts a word into the trie.
:type word: str
:rtype: void
"""
t = self.root
for c in word:
if c not in t:
t[c] = {}
t = t[c]
t[self.END] = {}
def search(self, word):
"""1
Returns if the word is in the trie.
:type word: str
:rtype: bool
"""
t = self.root
for c in word:
if c not in t:
return False
else:
t = t[c]
if self.END not in t:
return False
return True
def startsWith(self, prefix):
"""
Returns if there is any word in the trie that starts with the given prefix.
:type prefix: str
:rtype: bool
"""
t = self.root
for c in prefix:
if c not in t:
return False
else:
t = t[c]
return True
对于一个单词的查找一定编辑距离的相关集合的代码如下(from @Rshcaroline),其中的deque是python的高性能双向队列,用于将trie, word, path, edit_distance整个打包起来加入队列, 广度优先查找符合的单词
def get_candidate(trie, word, edit_distance=1):
que = deque([(trie, word, '', edit_distance)])
while que:
trie, word, path, edit_distance = que.popleft()
if word == '':
if END in trie:
yield path
# 词尾增加字母
if edit_distance > 0:
for k in trie:
if k != END:
que.appendleft((trie[k], '', path+k, edit_distance-1))
else:
if word[0] in trie:
# 首字母匹配成功
que.appendleft((trie[word[0]], word[1:], path+word[0], edit_distance))
# 无论首字母是否匹配成功,都如下处理
if edit_distance > 0:
edit_distance -= 1
for k in trie.keys() - {word[0], END}:
# 用k替换余词首字母,进入trie[k]
que.append((trie[k], word[1:], path+k, edit_distance))
# 用k作为增加的首字母,进入trie[k]
que.append((trie[k], word, path+k, edit_distance))
# 删除目标词首字母,保持所处结点位置trie
que.append((trie, word[1:], path, edit_distance))
# 交换目标词前两个字母,保持所处结点位置trie
if len(word) > 1:
que.append((trie, word[1]+word[0]+word[2:], path, edit_distance))