字典树
作用:快速实现查询某一个字符串是否出现过,类似字符串哈希
时复:O(L) [L:要查询的字符串长度]
空间复杂度:正比于需要插入的字符串总量,比普通数组存储要省空间
大致过程
每一个节点代表一个字符,根节点为0,从根节点到叶子节点是一个完整的字符串,实际上就是一个前缀树,两个相同前缀的字符串在字典树上就有一个相同的前缀路径,给每一个节点编一个号,从1开始,用一个二维数组,第一维表示编号,第二维表示字符下标(s[i]-‘a’),来表示这个编号的节点下有没有这个字符,这样一来省去了相同前缀的空间,而且查询可以每次以O(1)时间查询当前编号下是否有查询字符,需要查询L次,所以是O(L)
例题
洛谷模板P2580
题意
给定n个字符串,m次询问,每次询问一个给定字符串是否出现过?
题解
两种做法:
- map
- trie字典树
CODE
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 
 | #include <bits/stdc++.h>
 
 #define debug freopen("in.txt","r",stdin); freopen("out.txt","w",stdout)
 #define ios ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
 using namespace std;
 typedef long long ll;
 typedef unsigned long long ull;
 const int MAXN=1e6+100;
 const int MOD=1e9+7;
 const int INF=0x3f3f3f3f;
 const int SUB=-0x3f3f3f3f;
 const double eps=1e-4;
 const double E=exp(1);
 const double pi=acos(-1);
 int nex[MAXN][27];
 bool exist[MAXN];
 int tot;
 void insert(string s){
 int len=s.size(),p=0;
 for(int i=0;i<len;i++){
 int c=s[i]-'a';
 if(!nex[p][c]) nex[p][c]=++tot;
 p=nex[p][c];
 }
 return ;
 }
 int find(string s){
 int len=s.size(),p=0;
 for(int i=0;i<len;i++){
 int c=s[i]-'a';
 if(!nex[p][c]) return 0;
 p=nex[p][c];
 }
 if(!exist[p]){
 exist[p]=1;
 return 1;
 }
 return 2;
 }
 int main(){
 ios;
 int n,m;
 cin>>n;
 for(int i=1;i<=n;i++){
 string now;
 cin>>now;
 insert(now);
 }
 cin>>m;
 while(m--){
 string now;
 cin>>now;
 int k=find(now);
 if(k==0) cout<<"WRONG\n";
 else if(k==1) cout<<"OK\n";
 else cout<<"REPEAT\n";
 }
 
 return 0;
 }
 
 |