详解前缀树「TrieTree」

208. 实现 Trie (前缀树)

648. 单词替换

211. 添加与搜索单词 - 数据结构设计

677. 键值映射

676. 实现一个魔法字典

745. 前缀和后缀搜索

6183. 字符串的前缀分数和

 

「前缀树」又叫「字典树」或「单词查找树」,总之它们是一个意思!

「前缀树」的应用场景:给定一个字符串集合构建一棵前缀树,然后给一个字符串,判断前缀树中是否存在该字符串或者该字符串的前缀

可以结合题目 单词替换 理解!我们需要根据dictionary构建前缀树,然后判断sentence中的每个单词是否在前缀树中

分析

一般而言,字符串的集合都是仅由小写字母构成,所以本文章都是基于该情况展开分析!

字符串集合:[them, zip, team, the, app, that]。这个样例的前缀树长什么样呢?

1

由于都是小写字母,所以对于每个节点,均有 26 个孩子节点,上图中没有画出来,省略了而已...,但是要记住:每个节点均有 26 个孩子节点

还有一个点要明确:节点仅仅表示从根节点到本节点的路径构成的字符串是否有效而已

对于上图中橙色的节点,均为有效节点,即:从根节点到橙色节点的路径构成的字符串均在集合中

如果现在要找前缀te是否存在,分两步:

数据结构

现在看看如何表示这棵「前缀树」,即数据结构该如何定义。其实就是一棵多叉树,有 26 个孩子节点的多叉树而已!!

现在来思考节点的值又该如何表示呢?

在上面的例子中,节点仅仅表示路径构成的字符串是否有效而已,所以节点可以用boolean类型来表示

还有一类情况就是每个字符串都有一个权值,所以节点的值可以用一个数值来表示

常用操作

根据上面的分析,其实「前缀树」常用操作就三种

构建前缀树

最初,我们只有一个根节点root,孩子节点也都还没初始化!

所以直接看代码:

为了扩展思维,这里再给出递归的实现方法:(和树的遍历很像)

寻找目标字符串

当「前缀树」构建好了后,寻找目标字符串也就大同小异了

复习一下寻找的两个步骤:

同样的,为了扩展思维,这里再给出递归的实现方法:(和树的遍历很像)

寻找最短前缀

和「寻找目标字符串」差不多,但又有些许不同

高级操作

含有通配符的寻找

顾名思义,.可以表示任何字符。比如:a.c是可以和[abc, aec]匹配的

题目实战

实现 Trie (前缀树)

题目详情可见 实现 Trie (前缀树)

单词替换

题目详情可见 单词替换

添加与搜索单词 - 数据结构设计

题目详情可见 添加与搜索单词 - 数据结构设计

键值映射

题目详情可见 键值映射

这个题目些许不同,每个节点表示的不再是是否有效,而是一个值

实现一个魔法字典

题目详情可见 实现一个魔法字典

由于本题目必须替换一次,所以采取了一个傻办法:遍历每一种替换的情况

前缀和后缀搜索

题目详情可见 前缀和后缀搜索

前面的题目,节点表示的要么是有效性,要么是字符串的权值,而这个题目需要从前缀和后缀同时搜索 🔍

我们的可以采取的思路:同时维护两棵树 -> 「前缀树」和「后缀树」,树的每个节点表示以「从根节点到该节点路径构成的字符串」为前缀的单词的下标

表述的可能比较抽象,直接看图:(我们还是以[them, zip, team, the, app, that]这个样例为基础)

4

当我们需要寻找以t为前缀,以m为后缀的下标最大的字符串

显然我们可以很容易找到图中绿色的两个节点,对应的下标List[0, 2, 3, 5][0, 2]

解释:以 t 为前缀的单词有[them, team, the, that],其对应的下标为[0, 2, 3, 5]

同理:以 m 为后缀的单词有[them, team],其对应的下标为[0, 2]

然后根据有序链表合并的思路,从后往前找到第一个相同的下标,即为最大下标!!

字符串的前缀分数和

题目详情可见 前缀和后缀搜索

这个题也是「前缀树」的模版题,只不过每个节点的含义需要重新定义一下:表示以该路径为前缀的单词数量

可能表述的有些抽象,以["abc","ab","bc","b"]为例,直接看图:

432

构建好了前缀树,如果我们需要查询某个单词的前缀分数和,如"abc",只需要路径abc的节点累加即可,2 + 2 + 1 = 5

下面给出代码: