字符串算法整理
kmp 算法
先让模式串匹配自己,得出 $next$ 数组(实际是某段字符串的最长公共前后缀),在匹配时跳过多余的错误字符。
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 5 using namespace std; 6 7 int nxt[1000010]; 8 int la,lb,j; 9 char a[1000010],b[1000010]; 10 11 int main(){ 12 scanf("%s",a+1); 13 scanf("%s",b+1); 14 la=strlen(a+1); 15 lb=strlen(b+1); 16 for (int i=2;i<=lb;i++){ 17 while(j&&b[i]!=b[j+1])j=nxt[j];//不断跳找是否有其他的nxt 18 if(b[j+1]==b[i])j++;//在原来基础上扩展 19 nxt[i]=j; 20 } 21 j=0; 22 for(int i=1;i<=la;i++){ 23 while(j>0&&b[j+1]!=a[i]) 24 j=nxt[j];//失配就跳 25 if(b[j+1]==a[i]) 26 j++;//能匹配 27 if (j==lb){ 28 printf("%d\n",i-lb+1);//读位置 29 j=nxt[j]; 30 } 31 } 32 for (int i=1;i<=lb;i++) 33 printf("%d ",nxt[i]); 34 return 0; 35 }
manacher 算法
线性时间寻找回文串,利用对称性类似于单调扩展(不知道单调扩展是什么东西
code:
1 #include<cstdio> 2 #include<iostream> 3 4 using namespace std; 5 6 const int N=11000007; 7 char ch[N<<1]; 8 int p[N<<1]; 9 int cnt,ans=-0x7fffffff; 10 11 void scanFChar(){ 12 cnt=1; 13 ch[0]='~',ch[cnt]='|'; 14 char c=getchar(); 15 while(c>='a'&&c<='z'){ 16 ch[++cnt]=c;ch[++cnt]='|'; 17 c=getchar(); 18 } 19 }//读入 20 21 int main(){ 22 scanFChar(); 23 //r:最右回文串的右边界,mid:最右回文串的回文中心 24 for(int i=1,r=0,mid=0;i<=cnt;i++){ 25 if(i<=r) p[i]=min(p[(mid<<1)-i],r-i+1); 26 while(ch[i-p[i]]==ch[i+p[i]]) p[i]++; 27 if(p[i]+i>r) r=p[i]+i-1,mid=i; 28 ans=max(ans,p[i]);//最大的串场就是回文半径长减1(因为有'|'的加入) 29 } 30 printf("%d",ans-1); 31 return 0; 32 }
Trie
通过建立公共前缀链构成树,以空间换时间
code:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 7 using namespace std; 8 9 const int N=5e6+10; 10 int n,m; 11 char ch[55]; 12 bool vis[N],tot[N]; 13 int t[N][27],cnt,root; 14 15 void insert(char ch[]){ 16 int len=strlen(ch); 17 root=0; 18 for(int i=0;i<=len-1;i++){ 19 int k=ch[i]-'a'; 20 if(!t[root][k]) t[root][k]=++cnt; 21 root=t[root][k];//向下走建字符链 22 } 23 vis[root]=1; 24 } 25 26 int fiNd(char ch[]){ 27 int len=strlen(ch); 28 root=0; 29 for(int i=0;i<=len-1;i++){ 30 int k=ch[i]-'a'; 31 if(!t[root][k]) return 0;//没有这个字符 32 root=t[root][k];//不断向下爬 33 } 34 if(!vis[root]) return 0;//有前缀无单词 35 else{ 36 if(!tot[root]){ 37 tot[root]=1; 38 return 1;//第一次查询,打标记 39 } 40 else return 2; 41 } 42 } 43 44 int main(){ 45 scanf("%d",&n); 46 getchar(); 47 while(n--){ 48 scanf("%s",ch); 49 insert(ch); 50 } 51 scanf("%d",&m); 52 getchar(); 53 while(m--){ 54 scanf("%s",ch); 55 if(fiNd(ch)==1) printf("OK"); 56 else if(fiNd(ch)==2) printf("REPEAT"); 57 else if(fiNd(ch)==0) printf("WRONG"); 58 printf("\n"); 59 } 60 return 0; 61 }
AC 自动机
PAM 回文自动机
trie 树上挂回文串,还有一点 fail 指针提速
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 6 using namespace std; 7 8 const int N=5e5+10; 9 char ch[N]; 10 int t[N][27],len[N],fail[N],num[N],c,ans,pos,last,x; 11 int tot=1; 12 13 int geTFail(int pos,int x){ 14 while(x-len[pos]-1<0||ch[x-len[pos]-1]!=ch[x]) pos=fail[pos]; 15 return pos; 16 } 17 18 int main(){ 19 scanf("%s",ch); 20 int n=strlen(ch); 21 fail[0]=1;len[1]=-1; 22 for(int i=0;i<n;i++){ 23 if(i>=1) ch[i]=(ch[i]+last-97)%26+97; 24 pos=geTFail(x,i); 25 if(!t[pos][ch[i]-'a']){ 26 fail[++tot]=t[geTFail(fail[pos],i)][ch[i]-'a']; 27 t[pos][ch[i]-'a']=tot; 28 len[tot]=len[pos]+2; 29 num[tot]=num[fail[tot]]+1; 30 } 31 x=t[pos][ch[i]-'a']; 32 last=num[x]; 33 printf("%d ",last); 34 } 35 return 0; 36 }

浙公网安备 33010602011771号