大白书型模板,并没有写成函数形式:
这个是下标从0开始的:
此外,对于一个长度为 m 的串自匹配,在此模板中 m-p[m] 就是这个串的最小循环节长度(最后一个循环可以不完整)
另一个关于自匹配后的失配指针的性质:对于该串的所有可以作为循环节的长度是:m-p[m] , m-p[p[m]] , m-p[p[p[m]]]……直到 p[x] = 0。
1 #include<stdio.h>
2 #include<string.h>
3
4 const int maxn=1e6+5;
5 const int maxm=1e4+5;
6
7 char s[maxn],t[maxm]; //s为待匹配串,t为模板串
8 int p[maxm]; //自匹配数组
9
10 int main(){
11 while(scanf("%s%s",s,t)!=EOF){ //这个是字符串从下标0开始的
12 int i,j,ans=0; //ans记录字符串出现次数
13 int n=strlen(s),m=strlen(t); //在题目中遇到过,其实strlen很慢,所以如果不先存起来可能有TLE的风险
14 p[0]=p[1]=0; //初始化自匹配数组
15 for(i=1;i<m;i++){ //自匹配
16 j=p[i];
17 while(j&&t[i]!=t[j])j=p[j];
18 p[i+1]=t[i]==t[j]?j+1:0;
19 }
20 j=0; //注意 j=0
21 for(i=0;i<n;i++){ //串匹配
22 while(j&&s[i]!=t[j])j=p[j];
23 if(s[i]==t[j])j++;
24 if(j==m){
25 ans++; //此处记录出现次数(模板串在待匹配串中可重叠),或改为直接break表示是否出现过
26 }
27 }
28 printf("%d\n",ans);
29 }
30 return 0;
31 }
数组下标从1开始:
1 #include<stdio.h>
2 #include<string.h>
3
4 const int maxn=1e6+5;
5 const int maxm=1e4+5;
6
7 char s[maxn],t[maxm];
8 int p[maxm];
9
10 int main(){
11 while(scanf("%s%s",s+1,t+1)!=EOF){ // 。。这个是从下标1开始的,恩修改的还是比较多的所以不是很建议
12 int i,j,ans=0;
13 int n=strlen(s+1),m=strlen(t+1);
14 p[1]=p[2]=1;
15 for(i=2;i<=m;i++){
16 j=p[i];
17 while(j>1&&t[i]!=t[j])j=p[j];
18 p[i+1]=t[i]==t[j]?j+1:1;
19 }
20 j=1;
21 for(i=1;i<=n;i++){
22 while(j>1&&s[i]!=t[j])j=p[j];
23 if(s[i]==t[j])j++;
24 if(j==m+1){
25 ans++;
26 }
27 }
28 printf("%d\n",ans);
29 }
30 return 0;
31 }