字典树
引入
如果你要查询很多字符串的前缀(后缀)为字符串\(s\)的数量有多少个
这个时候就要运用到字典树
字典树的复杂度可以达到\(O(s.size())\)
性质
字典树这颗树有点特殊,别人记录的信息都在节点上,这棵树记录的信息在边上
从oi-wiki
上面 偷张图来看
可以发现,这棵字典树用边来代表字母,而从根结点到树上某一结点的路径就代表了一个字符串。举个例子,\(1\rightarrow4\rightarrow8\rightarrow 12\)表示的就是字符串 caa
。
那么节点有什么用呢,显然也不能浪费掉它的作用
-
节点可以记录到根节点到这个节点的字符串的数量
-
也能记录这颗子树的数量,即有多少个前缀为根节点到这个节点的字符串的数量
显然每个节点最多可能有\(26\)条边
那么空间复杂度就是\(n\times len \times 26\)
模板题
代码
#include<bits/stdc++.h>
#define fi first
#define se second
#define debug cout<<"I AM HERE"<<endl;
using namespace std;
typedef long long ll;
const int maxn=1e4+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-6;
int n,m;
char s[55];
struct trie {
int nex[500000+5][26], cnt;
int exist[500000+5]; // 该结点结尾的字符串是否存在
void insert(char *s, int l) { // 插入字符串
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!nex[p][c]) nex[p][c] = ++cnt; // 如果没有,就添加结点
p = nex[p][c];
}
exist[p] = 1;
}
int find(char *s, int l) { // 查找字符串
int p = 0;
for (int i = 0; i < l; i++) {
int c = s[i] - 'a';
if (!nex[p][c]) return 0;
p = nex[p][c];
}
if(exist[p]) exist[p]++;
return exist[p];
}
}a;
signed main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%s",s);
a.insert(s,strlen(s));
}
scanf("%d",&m);
for(int i=1;i<=m;i++){
scanf("%s",s);
if(a.find(s,strlen(s))==2){
printf("OK\n");
}else if(a.find(s,strlen(s))>2){
printf("REPEAT\n");
}else{
printf("WRONG\n");
}
}
return 0;
}
不摆烂了,写题