字典树可以用来快速的求解前缀相关的问题
字典树相关题目:H6183 M208
M208时前缀树的模板,但是实现起来优点冗杂
字典树就是一个26叉树,但是下面的实现方式是使用的字典,不太好理解,因为它将字母以键的形式进行记录,而值却是一个新的节点
class Node:
def __init__(self):
# 使用字典操作起来比较快,这个字典的键就是26个英文字母中的一个,值就是
# 跟这个节点一样的节点
self.son = defaultdict(Node)
# val就是这个节点(字母)遍历到的的次数
self.val = 0
# val就是哪些单词以这个节点为结尾
self.ids = []
# 如何将一连串的字符放进字典树中
words = ["abc", "ab", "bc", "b"]
root = Node()
for ind, word in enumerate(words):
# 对于每一个单词都要从第一个节点开始
cur_node = root
for c in word:
cur_node = cur_node.son[c]
# 经过cur_node的字符的个数
cur_node.val += 1
# 以这个字母为结尾的单词的索引
cur_node.ids.append(ind)
使用哈希表表示节点属于进阶做法,一般情况下会使用[None]*26的列表来表示self.son,这样会浪费大量的时间和空间,但是对于理解字典树还是很有帮助的。
传统的字典树节点结构如下,里面的具体的属性会根据题目的不同而改变:
class node:
# 使用ids记录以这个节点结尾的单词的索引,比直接使用is_end更好
# son就是记录哪一个位置有下一个节点,一个个遍历,不为None的位置的索引可以用来反推出字母
# score可以用来记录我这个节点被遍历了多少次了,可以用来统计以这个字母为前缀的单词的数量
def __init__(self):
self.son = [None] * 26
self.score = 0
self.ids = []
如何构造前缀树,对于一个单词列表 words = [“abc”, “ab”, “bc”, “b”] :
# 首先创建根节点,根节点不保存数据,只用来向下推
root = Node()
for ind, word in enumerate(words):
# 对于每一个单词都要从第一个节点开始
cur_node = root
for c in word:
cur_node = cur_node.son[c]
# 经过cur_node的字符的个数
cur_node.val += 1
# 以这个字母为结尾的单词的索引
cur_node.id.append(ind)
如何遍历字典树,如果需要通过字典树反推出原来的单词列表,可以使用dfs深度优先搜索:
n = len(words)
ans = [0] * n
def f(node, t, ind):
if not node:
return
if ind!=-1:
t+=chr(ind+97)
for j in node.ids:
ans[j] = t
for ind, i in enumerate(node.son):
if i:
f(i, t, ind)
f(root, '',-1)
print(ans)
进阶一点的用法就是用哈希表(字典)替换列表,从而使占用的内存更小,速度更快。
见:H6183 灵佬解答
如何向已经建好的字典树中插入一个单词:
w = 'poiuytre'
# 这里的root是前面创建字典树时创建的根节点,这里是插入操作!
cur = root
for i in w:
if cur.son[ord(i) - 97]:
cur.score += 1
else:
cur.son[ord(i) - 97] = node()
cur.score += 1
# 操作完毕,将cur指向下一个节点
cur = cur.son[ord(i) - 97]
cur.ids.append(-1) # 他不在列表中