做每日一题看到题解需要用到前缀树,之前完全没听说过。于是就打算好好学习一下。
前缀树定义
Leetcode #208
Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
请你实现 Trie 类:
Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
前缀树实现
不看题解真的不太能理解前缀树到底干了啥,但是看了题解之后就发现前缀树也挺简单的。它可以理解成为一个26叉树,每一个叉对应一个字符。并且每个节点要记录是不是结尾,来判断当前路径能不能构成一个字符串(一个节点可以是结尾,也可以继续指向下一个Trie)
1 | class Trie { |
在官方题解评论中看到一个更好的版本。因为search和startWith前面其实做的事情差不多,所以可以写一个searchPrefix函数来搜索前缀,简化下代码。并且可以用一个数组来记录new生成的node,最后在析构的时候delete掉。
1 | struct Node{ |
前缀树应用
单词的压缩编码
Leetcode #820
单词数组 words 的 有效编码 由任意助记字符串 s 和下标数组 indices 组成,且满足:
words.length == indices.length
助记字符串 s 以 ‘#’ 字符结尾
对于每个下标 indices[i] ,s 的一个从 indices[i] 开始、到下一个 ‘#’ 字符结束(但不包括 ‘#’)的 子字符串 恰好与 words[i] 相等
给你一个单词数组 words ,返回成功对 words 进行编码的最小助记字符串 s 的长度 。
示例 1:
输入:words = [“time”, “me”, “bell”]
输出:10
解释:一组有效编码为 s = “time#bell#” 和 indices = [0, 2, 5] 。
words[0] = “time” ,s 开始于 indices[0] = 0 到下一个 ‘#’ 结束的子字符串,如加粗部分所示 “time#bell#”
words1 = “me” ,s 开始于 indices1 = 2 到下一个 ‘#’ 结束的子字符串,如加粗部分所示 “time#bell#”
words2 = “bell” ,s 开始于 indices2 = 5 到下一个 ‘#’ 结束的子字符串,如加粗部分所示 “time#bell#”
示例 2:
输入:words = [“t”]
输出:2
解释:一组有效编码为 s = “t#” 和 indices = [0] 。
提示:
1 <= words.length <= 2000
1 <= words[i].length <= 7
words[i] 仅由小写字母组成
这题可以用前缀树来做,不过要把单词反转过来,并且要将单词从长到短排序加入到前缀树中。
1 | class Trie{ |
参考资料
前缀树介绍和实现:
https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/trie-tree-de-shi-xian-gua-he-chu-xue-zhe-by-huwt/
https://blog.csdn.net/m0_46202073/article/details/107253959
Merkle Patricia Tree:
https://ethfans.org/toya/articles/588