字符串数据结构模板
Trie 树
字典树,用于存储和查询数量较大的字符串。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define maxn 500010 5 using namespace std; 6 char aa[51]; 7 8 struct Trie { 9 int sz; 10 int ch[maxn][26]; 11 int val[maxn]; 12 Trie() { sz=1; memset(ch[0],0,sizeof(ch[0])); } 13 int idx(char x) {return x-'a';} 14 void insert(char *s) { 15 int n=strlen(s); 16 int u=0; 17 for (int i=0; i<n;i++) { 18 int c=idx(s[i]); 19 if(!ch[u][c]) { 20 memset(ch[sz],0,sizeof(ch[sz])); 21 val[sz]=0; 22 ch[u][c]=sz++; 23 } 24 u=ch[u][c]; 25 } 26 val[u]=1; 27 } 28 void check(char *s) { 29 int n=strlen(s); 30 int u=0; 31 for (int i=0;i<n;i++) { 32 int c=idx(s[i]); 33 if(!ch[u][c]) { cout<<"WRONG\n"; return;} 34 u=ch[u][c]; 35 } 36 if(val[u]==1) {cout<<"OK\n"; val[u]++;} 37 else if(val[u]>1) cout<<"REPEAT\n"; 38 else cout<<"WRONG\n"; 39 return; 40 } 41 }trie; 42 43 int main() { 44 int n; 45 cin>>n; 46 for (int i=1;i<=n;i++) { 47 scanf("%s", aa); 48 trie.insert(aa); 49 } 50 cin>>n; 51 for (int i=1;i<=n;i++) { 52 scanf("%s", aa); 53 trie.check(aa); 54 } 55 return 0; 56 }
例题:洛谷P2580
KMP算法
支持单个模式串匹配。
思想:用自己匹配自己。核心是next数组。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <string> 5 using namespace std; 6 string s1, s2; 7 int len1, len2; 8 int next[1001]; 9 10 void NEXT_init(){ 11 for (int i=1;i<len2;i++) { 12 int j=next[i-1]; 13 while (j && s2[j]!=s2[i]) 14 j=next[j-1]; 15 if(s2[i]==s2[j]) j++; 16 next[i]=j; 17 } 18 return ; 19 } 20 21 void kmp() { 22 int j=0; 23 for (int i=0;i<len1;i++) { 24 while(j && s1[i]!=s2[j]) 25 j=next[j-1]; 26 if (s1[i]==s2[j]) 27 j++; 28 if(j==len2) 29 cout<<i-j+2<<endl; 30 } 31 return ; 32 } 33 34 int main() { 35 cin>>s1>>s2; 36 len1=s1.length(); 37 len2=s2.length(); 38 NEXT_init(); 39 kmp(); 40 for (int i=0; i<len2; i++) 41 cout<<next[i]<<" "; 42 return 0; 43 }
例题:洛谷P3375
AC自动机
支持多模式串匹配。
思想:Trie树+KMP算法;也可以看做模式串有多个的KMP算法在Trie树上的实现。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using namespace std; 6 const int maxn 50010 7 int tot, n; 8 char s[50]; 9 10 struct Trie { 11 int sz; 12 int ch[maxn][26]; 13 int val[maxn]; 14 int f[maxn]; 15 Trie() { sz=1; memset(ch[0],0,sizeof(ch[0]));} 16 int idx(char x) { return x-'a'; } 17 18 void insert(char *s) { 19 int u=0, n=strlen(n); 20 for (int i=0;i<n;i++) { 21 int c=idx(s[i]); 22 if (!ch[u][c]) { 23 memset(ch[sz],0,sizeof(ch[sz])); 24 val[sz]=0; 25 ch[u][c]=sz++; 26 } 27 u=ch[u][c]; 28 } 29 val[u]=++tot; 30 return ; 31 } 32 33 void getFail() { 34 queue <int> q; 35 f[0]=0; 36 for (int i=0; i<26; i++) { 37 int u=ch[0][i]; 38 if (u) { 39 f[u]=0; 40 q.push(u); 41 last[u]=0; 42 } 43 } 44 while (!q.empty()) { 45 int r=q.front(); 46 q.pop(); 47 for (int i=0; i<26; i++) { 48 int u=ch[r][i]; 49 if (!u) continue; 50 q.push(u); 51 int v=f[r]; 52 while(v && !ch[v][i]) v=f[v]; 53 f[u]=ch[v][i]; 54 last[u]=val[f[u]]? f[u]:last[f[u]]; 55 } 56 } 57 return ; 58 } 59 60 void find(char *t) { 61 int n=strlen(t); 62 int j=0; 63 for (int i=0; i<n; i++) { 64 int c=idx(t[i]); 65 while (j && !ch[j][c]) j=f[j]; 66 j=ch[j][c]; 67 if (val[j]) print(i,j); 68 else if(last[j]) print(i, last[j]); 69 } 70 return ; 71 } 72 }trie; 73 74 75 void print(int i, int j) { 76 if (j) 77 printf("%d : %d", i, val[j]); 78 print(i, last[j]); 79 return ; 80 }
Manacher
最长回文串的计算。
核心思想是把已经计算过的回文部分“抄过来”。
1 #include <iostream> 2 #include <cstdio> 3 #include <string> 4 using namespace std; 5 6 string a, a1; 7 int lena, p[100010]; 8 int maxn=0; 9 10 int max(int x, int y) {return x>y?x:y;} 11 int min(int x, int y) {return x<y?x:y;} 12 13 void manacher() { 14 int mx, id; 15 mx=id=0; 16 for (int i=1; i<=lena; i++) { 17 if (mx>i) 18 p[i]=min(mx-i, p[id*2-i]); 19 while (a[i+p[i]]==a[i-p[i]]) 20 p[i]++; 21 if (mx<p[i]) { 22 mx=i+p[i]; id=i; 23 } 24 } 25 for (int i=1; i<=lena; i++) 26 maxn=max(maxn,p[i]); 27 maxn--; 28 return ; 29 } 30 31 int main() { 32 cin>>a1; 33 lena=a1.length(); 34 a+="$#"; 35 for (int i=0; i<lena; i++) { 36 a+=a1[i]; 37 a+="#"; 38 } 39 lena<<=1; 40 manacher(); 41 cout<<maxn; 42 return 0; 43 }
字符串Hash
不属于数据结构,但由于也与字符串有关,也放在这里。
使用BKDRHash和APHash
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 unsigned int BKDRHash(char *str) { 7 unsigned int seed = 31; // 31 131 1313 13131 131313 etc.. 8 unsigned int hash = 0; 9 while (*str) 10 hash = hash*seed+(*str++); 11 return (hash & 0x7FFFFFFF); 12 } 13 14 15 int APhash1() { 16 int k(0), len = _str.length(); 17 for (int i = 0; i < len; ++i) 18 k = ((_str[i] * (i + 1)) % INF + k) % INF; 19 return k % INF; 20 21 22 unsigned int APHash2(char *str) { //不是很懂的版本,求大佬讲解 23 unsigned int hash = 0; 24 int i; 25 for (i=0; *str; i++) 26 if (!(i&1)) 27 hash^=((hash<<7)^(*str++)^(hash>>3)); 28 else 29 hash^=(~((hash<<11)^(*str++)^(hash>>5))); 30 return (hash&0x7FFFFFFF); 31 }
代码出处 BKDRHash & APHash1 APHash2