前言
下标计数对各位而言再平常不过,使用数组或者map等均可实现。
但是它们常常有限制约束——下标过大、时间复杂度要求过高、字符串等,这就很麻烦了……
此时,字典树的用处就出来了。
关于字典树
图1
以字符串为例,将一个单词拆分为若干字母,存入如图1的树状图中,并用数字为每个节点标序号,以树的方式访问。同样的,数字有关的也可以像这样储存。
Trie VS map
Map实现的是哈希表,用于解决的精确查找,使用key-value存储,十分常用。
Trie字典树,用于解决前缀检索(模糊查找)——当然也可以演化出后缀树,解决后缀检索问题。
Trie能解决map的问题,因为(精准检索本来就的一个特例),只不过速度没map快。而多数时候map不能解决Trie的问题。
辩证的看待
优点:最大限度地减少无谓的字符串比较,查询效率高、适用范围广()
缺点:采用空间换时间的策略,占用内存大。
应用范围:
1. 快速检索。字典树对复杂内容进行数字映射(如将字符串映射为数字,比如瑞瑞的木棍 - 洛谷这道题就可以这么做)
2. “串”排序类。假设给定若干个互不相同的英文单词,让你将他们按字典序从小到大输出用字典树进行排序,采用数组的方式创建字典树,这棵树的每个结点的所有儿子很显然地按照其字母大小排序,于是对这棵树进行先序遍历即可。
3. 最长公共前缀类。对所有串建立字典树,对于两个串的最长公共前缀的长度即他们所在的结点的公共祖先个数,把问题转化为最近公共祖先问题。
代码实现
以判断是否存在单词为例。
建树(插入)——代码实现:
void charu(char s[])
{
ll p=0,t;
for(int i=0;i<strlen(s);i++)
{
t=change(s[i]);
if(!f[p][t])f[p][t]=++idx;
p=f[p][t];
}
end[p]=1;
}
查询——代码实现:
bool chaxun(char s[])
{
ll p=0,t;
for(int i=0;i<strlen(s);i++)
{
t=change(s[i]);
if(!f[p][t])return 0;
p=f[p][t];
}
return end[p];
}
可根据实际情况对代码进行修改。