版权声明:转载请注明出处 https://blog.csdn.net/weixin_42557561/article/details/83891969
- 哈希(字符串的常规处理)
- KMP(字符串匹配)
- Manacher(最长回文子串)
- Trie树(用处可多了。)
哈希
char st[2000];
map<ULL,bool> M;
inline void hash(int len){
ULL res=0;
for(int i=0;i<len;++i){
res=res*b+st[i];
}
if(!M[res]) ans++,M[res]=1;
}
KMP
一定要明确nxt数组的含义
很多题可以转化为KMP都是牵扯到了nxt的含义
所以nxt[i]是什么呢?
就是当前这位i的前缀中,前缀与后缀相同的最长的长度
记个结论吧:
一个字符串的最小循环节长度就是 ,个数就是 ,如果除不尽就不是完全循环得到的,需要补充的字符串个数为(令最小循环节的长度为L): %L
nxt[1]=0;j=0;
for(i=2;i<=lenb;++i){
while(j&&b[j+1]!=b[i]) j=nxt[j];
if(b[j+1]==b[i]) j++;
nxt[i]=j;
}
for(i=1;i<=lena;++i){
while(j&&b[j+1]!=a[i]) j=nxt[j];
if(b[j+1]==a[i]) j++;
if(j==lenb){
ans++;//根据题目要求进行相应的更改
j=nxt[j];
}
}
Manacher
#include<bits/stdc++.h>
#define N 11000009
using namespace std;
char st[N],stn[N<<1];//注意空间
int ans=0,Len,len;
inline int change(){
int j=1;
stn[0]='$';
stn[1]='#';
for(int i=1;i<=len;++i){
stn[++j]=st[i];
stn[++j]='#';
}
stn[j+1]='\0';
return j;
}
int p[N<<1];
inline void manacher(){
int id=0,mx=0;
for(int i=1;i<=Len;++i){
if(i<mx) p[i]=min(p[2*id-i],mx-i);
else p[i]=1;
while(stn[i+p[i]]==stn[i-p[i]]) p[i]++;
if(i+p[i]>mx){
mx=i+p[i];
id=i;
}
ans=max(ans,p[i]-1);
}
}
int main(){
scanf("%s",st+1);
len=strlen(st+1);
Len=change();
manacher();
cout<<ans;
return 0;
}
Trie树
大致模板长这样,但还是有很多需要根据题意而改变的
inline void insert(char *t){
int p=0,len=strlen(t);
for(int i=0;i<len;++i){
int c=t[i]-'a';
if(!trie[p][c]) cnt[trie[p][c]=++tot]++;
else cnt[trie[p][c]]++;
p=trie[p][c];
}
}
inline int query(char *t){
int p=0,len=strlen(t);
for(int i=0;i<len;++i){
int c=t[i]-'a';
int num=trie[p][c];
if(num&&cnt[num]==1) return i;
p=trie[p][c];
}
return len-1;
}