字典树 前缀树

字典树可以用来快速的求解前缀相关的问题
字典树相关题目: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)  # 他不在列表中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值