字符串Hash
每个字符对于一个ASCII码,即可用一个数字表示
将字符串转换为一个p进制数(常取p=131)
hash代码如下:
const int p=131;
const int mod=99999991;
int Hash(string s){
int hash=0;
for(int i=0;i<strlen(s);i++)
hash=(hash*p+s[i])%mod;
return hash;
}
但单Hash仍比较容易发生冲突,所以可维护字符串长度来降低冲突。
STL_hash
unordered_map
unordered_set
例题
CF 955D Scissors
ICPC 2019 Shanghai Online Contest G
CF 985F Isomorphic Strings
二维Hash
横行求一遍hash值,数列再求一遍
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++)
v[i][j]=s[j]+v[i][j-1]*base1+v[i-1][j]*base2-v[i-1][j-1]*base1*base2;
}
ull c=1,d=1;
for(int i=1;i<=a;i++) d*=base2;
for(int i=1;i<=b;i++) c*=base1;
for(int i=a;i<=n;i++)
for(int j=b;j<=m;j++)
mp.insert(make_pair(v[i][j]-v[i][j-b]*c-v[i-a][j]*d+v[i-a][j-b]*c*d,1));
Trie树
又称字典树,单词查找树。
性质:
- 除根节点外,每个节点都包含一个字符
- 从根到某一节点所经过的路径上的字符相连,即为该节点对应的字符串
- 每个节点的子节点互不相同
代码如下:
建树
void insert(char *str){
int len=strlen(str),root=0;
for(int i=0;i<len;i++){
int id=str[i]-'0';
if(!tree[root][id]) tree[root][id]=++tot;
root=tree[root][id];
}
flagg[root]=true;
}
查询
bool find(char *str){
int len=strlen(str),root=0;
for(int i=0;i<len;i++){
int id=str[i]-'0';
if(!tree[root][id]) return false;
root=tree[root][id];
}
return true;
}
例题
LA3942 Remember the Word
Leetcoder421 Maximum XOR of Two Numbers in an Array
NEERC11D Dictionary Size
AC自动机
一种字符串匹配算法。适用于多模式串。
通过在trie树上维护失配边fail来实现。
建树
void insert(string s){
int root=0;
for(int i=0;i<s.size();i++){
int next=s[i]-'a';
if(!trie[root][next])
trie[root][next]=++cnt;
root=trie[root][next];
}
cntword[root]++;
}
void getfail(){
queue<int>q;
for(int i=0;i<26;i++){
if(trie[0][i]){
fail[trie[0][i]]=0;
q.push(trie[0][i]);
}
}
while(!q.empty()){
int now=q.front();
q.pop();
for(int i=0;i<26;i++){
if(trie[now][i]){
fail[trie[now][i]]=trie[fail[now]][i];
q.push(trie[now][i]);
}
else trie[now][i]=trie[fail[now]][i];
}
}
}
查询
int find(string s){
int now=0,ans=0;
for(int i=0;i<s.size();i++){
now=trie[now][s[i]-'a'];
for(int j=now;j&&cntword[j]!=-1;j=fail[j]){
ans+=cntword[j];
cntword[j]=-1;
}
}
return ans;
}
性质
每个节点不仅是一个单词的结尾,也包含了所有以它为结尾作为前缀的串
例题
JSOI2007文本生成器
2018 ACM-ICPC Beijing Onsite H Approximate Matching
HEOI2012旅行问题
KMP
一种字符串匹配算法。相当于退化的AC自动机,主要依赖于一个next数组
next数组表示:当前字符之前的字符串中,有多大长度的相同前缀后缀。
如何预处理出next数组?
next[0]=-1;
int j=-1;
for(int i=1;i<b.size();i++){
while((j>=0)&&(b[j+1]!=b[i])) j=next[j];
if(b[j+1]==b[i])j++;
next[i]=j;
}
匹配:
j=-1;
for(int i=0;i<a.size();i++){
while((j>-1)&&(b[j+1]!=a[i]))j=next[j];
if(b[j+1]==a[i])j++;
if(j==b.size()-1){
ans++;
j=next[j];
}
}
例题
HDU3336 Count the string
ZOJ1905 Power Strings
POI2006 OKR-PERIODS OF WORDS
扩展KMP
和kmp比较类似。
next数组的含义稍有不同,
next[i]表示t[i]…t[m-1]于t的最长相同前缀长度,即相当于t自己和自己匹配
当i+next[i-a]与p的大小关系不同时,答案extend[i]的值也不同。
- i+next[i-a]<p时,extend[i]=next[i-a]
- i+next[i-a]=p时,直接从s[p]与t[p-i]开始匹配
- i+next[i-a]>p时,extend[i]=p-i;
void pre_EKMP(char x[],int m,int nxt[])
{
nxt[0]=m;
int j=0;
while(j+1<m && x[j]==x[j+1]) j++;
nxt[1]=j;
int k=1;
for(int i=2;i<m;i++)
{
int p=nxt[k]+k-1;
int L=nxt[i-k];
if(i+L<p+1)nxt[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<m && x[i+j]==x[j])j++;
nxt[i]=j;
k=i;
}
}
}
void EKMP(char x[],int m,char y[],int n,int nxt[],int extend[])
{
pre_EKMP(x,m,nxt);
int j=0;
while(j<n && j<m && x[j]==y[j]) j++;
extend[0]=j;
int k=0;
for(int i=1;i<n;i++)
{
int p=extend[k]+k-1;
int L=nxt[i-k];
if(i+L<p+1)
extend[i]=L;
else
{
j=max(0,p-i+1);
while(i+j<n && j<m && y[i+j]==x[j]) j++;
extend[i]=j;
k=i;
}
}
}
例题
HDU2594 SIMPSONS’ HIDDEN TALENTS
2019 Multi-University,HDU Day5 D
Manacher
回文串有奇数偶数之分,若在每个字符之间插入一个#,在开头和结尾分别插入两个不常用的字符表示边界(如%、$、@…),即可将所有回文串变成奇数。
设p[i]表示以i为中心的最长回文的半径,p[i]-1即为回文串的长度。
所以怎么预处理出p数组呢?
- i>=maxright 中心扩散法
- i<maxright时
.1. p[mirror]<maxright时 p[i]=p[mirror]
.2. p[mirror]=maxright-i时 p[i]>=maxright-i,继续扩展
.3. p[mirror]>maxright-i时 p[i]=maxright-i
void init(){
len=strlen(s),cnt=1;
ss[0]='!';ss[cnt]='#';
for(int i=0;i<len;i++)
ss[++cnt]=s[i],ss[++cnt]='#';
}
void manacher(){
int pos=0,mx=0;
for(int i=1;i<=cnt;i++){
if(i<mx) p[i]=min(p[pos*2-i],mx-i);
else p[i]=1;
while(ss[i+p[i]]==ss[i-p[i]]) p[i]++;
if(mx<i+p[i]) mx=i+p[i],pos=i;
ans=max(ans,p[i]-1);
}
}
例题
2018 ICPC Nanjing Regional Contest M
NOWCODER14894 最长回文
POI2007 Axes of Symmetry