字典树学习
在某一天,小蒟蒻正在愉快的用暴力解决一道水题,却没想到超时了,经大佬讲解,才知道这是经典的字典树,膜拜dalao。( •̀ ω •́ )✧ ORZ
- 那么想要理解字典树,那么就要从最经典的查前前缀开始讲了
如果用暴力的话,直接一个个对比就可以了,但是在求最大公共前缀的个数时,一个个进行对比,当进行检测时,避免不了过多的数据,那么超时是必不可免的了,毕竟,这是做了大量的 无用功,而前缀树是建立一个表(像个树的表)。
那么基础的前缀树是啥样的呢?(字丑见谅)
也许大家看出来了,字母不在球内,而是在线上。
那么过程是如何实现的呢?
这就是建树的大致过程
那么我们如何将这个表记录下来呢?
从图中我们可以看出
trie tree的储存方式:将字母储存在边上,边的节点连接与它相连的字母
那么我们可以这么建树
trie[rt] [x]=tot[rt]是上个节点编号,x是字母,tot是下个节点编号
代码如下。
void insert(char *w){
int len = strlen(w);
int p = 0;
for(int i=0; i<len; i++){
int c = w[i] - 'a';
if(!trie[p][c]){
trie[p][c] = k;
k++;
}
p = trie[p][c];
}
color[p] = 1;
}
- 那么我们如何寻找前缀呢?
见下图
那么如何实现的呢?
上代码
int search(char *s){
int len = strlen(s);
int p = 0;
for(int i=0; i<len; i++){
int c = s[i] - 'a'; //主要经过这个定位,这也是为什么虚线出现的原因,因为这个位置没有具体值
if(!trie[p][c]) return 0;
p = trie[p][c];
}
return color[p] == 1; //判断是否有值,是的话返回1,否则为0;
}
好了,那么只差一个主函数把这些函数连起来
整体代码如下
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAX_NODE = 1000000 + 10;
const int CHARSET = 26;
int trie[MAX_NODE][CHARSET] = {0};
int color[MAX_NODE] = {0};
int k = 1;
void insert(char *w){
int len = strlen(w);
int p = 0;
for(int i=0; i<len; i++){
int c = w[i] - 'a';
if(!trie[p][c]){
trie[p][c] = k;
k++;
}
p = trie[p][c];
}
color[p] = 1;
}
int search(char *s){
int len = strlen(s);
int p = 0;
for(int i=0; i<len; i++){
int c = s[i] - 'a';
if(!trie[p][c]) return 0;
p = trie[p][c];
}
return color[p] == 1;
}
int main(){
int t,q;
char s[20];
scanf("%d%d", &t,&q);
while(t--){
scanf("%s", s);
insert(s);
}
while(q--){
scanf("%s", s);
if(search(s)) printf("YES\n");
else printf("NO\n");
}
return 0;
}
抽空,再讲讲变式吧。
好像挖坑了`(>﹏<)′