Trie树
Trie树又称字典树,前缀树。是一种可以
高效查询前缀字符串
的树,典型应用是用于统计
,排序和保存大量的字符串
(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间
,最大限度地减少无谓的字符串比较,查询效率比哈希树高。`做题看到大量字符串或者大量字符就往Trie树或者哈希这边想,因为速度很快
Trie树功能:
1、插入:
向字符串集合插入字符串
2、查询:
查询某个字符串是否在该字符串集合中(可以在字符串末尾的字符上打上一个标记)
3、统计次数:
统计某个字符串在该字符串集合中出现的次数
4、求最长前缀:
求两个字符串的最长公共前缀
以模板题:AcWing 835.Trie字符串统计来讲解插入和查询操作
解释:
a
r
r
arr
arr 数组是一个二维数组,比如这道题,它的列数应该是每个节点的最大分支数,也就是这里有
26
26
26 个字母,每个字母的下一个字母有
26
26
26 种情况,所以要开
26
26
26 列,在最大异或对这道题里面就只有
0
0
0 和
1
1
1 ,所以开两列就是了。行数的话就看题目的最大长度了
插入操作
void insert()
{
int p=0;//每次插入都是从第一行开始的,也就是p=0
for(auto ch:str)
{
int u=ch-'a';
if(!arr[p][u])//如果这个格子还没被用,那么就把这个字母放到这个格子
arr[p][u]=++idx;
p=arr[p][u];//指向下一个
}
++cnt[p];//该字符串数目+1
}
假如依次插入
a
b
,
a
b
c
,
a
d
b
,
ab,abc,adb,
ab,abc,adb,
b
d
,
d
e
f
bd,def
bd,def
每一次插入的时候,
p
p
p都是从
0
0
0开始。如果首字母没出现过,一定在
a
r
r
arr
arr数组的第一行,第二字母及以后的字母才开始按照
i
d
x
idx
idx来找位置放,形成链表的结构,插入后的
a
r
r
arr
arr数组如下图,格子中的数字,即$idx$表示下一个字母应该放在第几行
查询字符串出现多少次
int query()
{
int p=0;
for(auto ch:str)
{
int u=ch-'a';
if(!arr[p][u])//如果不存在,说明这个字符串不存在,直接返回0
return 0;
p=arr[p][u];
}
return cnt[p];//返回这个字符串出现的次数
}
用cnt数组保存每个字符串出现的次数,在cnt中用的是最后一个字母的idx来代表这个字符串,虽然idx是代表下一个字母出现的位置,但不影响
比如上面的
a
c
d
acd
acd 和
b
d
bd
bd ,
a
c
d
acd
acd 的
′
d
′
'd'
′d′ 的
i
d
x
idx
idx 是
4
4
4 ,那么
c
n
t
[
4
]
cnt[4]
cnt[4] 就代表了
a
b
d
abd
abd 这个字符出现的次数,
b
d
bd
bd 的
′
d
′
'd'
′d′ 的
i
d
x
idx
idx 是
6
6
6,那么
c
n
t
[
6
]
cnt[6]
cnt[6] 就代表了
b
d
bd
bd 这个字符串出现的次数,因为对于每个字符串的结尾的
i
d
x
idx
idx 是不同的,那么每个
i
d
x
idx
idx 就对应了相应的字符串,不会出现重复的情况
T r i e Trie Trie树经典应用:AcWing 143.最大异或对