字典树
作用:快速实现查询某一个字符串是否出现过,类似字符串哈希
时复:O(L) [L:要查询的字符串长度]
空间复杂度:正比于需要插入的字符串总量,比普通数组存储要省空间
大致过程
每一个节点代表一个字符,根节点为0,从根节点到叶子节点是一个完整的字符串,实际上就是一个前缀树,两个相同前缀的字符串在字典树上就有一个相同的前缀路径,给每一个节点编一个号,从1开始,用一个二维数组,第一维表示编号,第二维表示字符下标(s[i]-‘a’),来表示这个编号的节点下有没有这个字符,这样一来省去了相同前缀的空间,而且查询可以每次以O(1)时间查询当前编号下是否有查询字符,需要查询L次,所以是O(L)
例题
洛谷模板P2580
题意
给定n个字符串,m次询问,每次询问一个给定字符串是否出现过?
题解
两种做法:
- map
- trie字典树
CODE
1 2 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; }
|