大白书型模板,并没有写成函数形式:
关于p数组(失配指针数组)的含义: - 数组下标从0开始
p[i]表示当发现待匹配串(s)已匹配位置与模板串(t)的t[i]不匹配时,t中最近一个可以尝试继续匹配的位置。即当已经完成了s串与t[0]~t[i-1]的匹配时,发现s串后一个字符与t[i]不匹配,此时s串到当前不构成匹配的位置前可以视为与 t[0] ~ t[ p[i]-1 ] 完成了匹配,因此可以继续匹配s串当前字符与 t[ p[i] ] 。此时如果仍然不匹配可以继续对 t 当前不匹配的位置做失配转跳,直至转跳到t中的当前匹配位置为0位置。
因此实际上p[i]也具有这样的性质:t[0]~t[ p[i]-1 ] 是 t[0]~t[i-1] 的所有前缀中的最长可匹配后缀。
此外,对于一个长度为 m 的串自匹配,在此模板中 m-p[m] 就是这个串的最小循环节长度(最后一个循环可以不完整) - 数组下标从0开始
另一个关于自匹配后的失配指针的性质:对于该串的所有可以作为循环节的长度是:m-p[m] , m-p[p[m]] , m-p[p[p[m]]]……直到 p[x] = 0。 - 数组下标从0开始
这个是下标从0开始的:
1 #include <stdio.h>
2 #include <string.h>
3 typedef long long ll;
4 #define MP make_pair
5 #define PB push_back
6 const int mod = 1e9 + 7;
7 const double eps = 1e-8;
8 const int INF = 0x3f3f3f3f;
9 const int maxn = 1e6 + 5;
10 const int maxm = 1e5 + 5;
11
12 char s[maxn],t[maxm]; //s为待匹配串,t为模板串
13 int p[maxn]; //自匹配数组
14
15 int main(){
16 int T;
17 scanf("%d",&T);
18 while(T--){
19 scanf("%s%s", t, s); //这个是字符串从下标0开始的
20 int i,j = 0,ans=0; // j = 0 注意, ans记录字符串出现次数
21 int n = strlen(s), m = strlen(t); //在题目中遇到过,其实strlen很慢,所以如果不先存起来可能有TLE的风险
22 p[0] = p[1] = 0; //初始化自匹配数组
23 for(i = 1 ; i < m ; ++ i){ //自匹配
24 while(j && t[i] != t[j])j = p[j];
25 if(t[i] == t[j])++ j;
26 p[i+1] = j;
27 }
28 j = 0; //注意 j=0
29 for(i = 0 ; i < n ; ++ i){ //串匹配
30 while(j && s[i] != t[j])j = p[j];
31 if(s[i] == t[j])++ j;
32 if(j == m){
33 ans++; //此处记录出现次数(模板串在待匹配串中可重叠),或改为直接break表示是否出现过
34 }
35 }
36 printf("%d
",ans);
37 }
38 return 0;
39 }
数组下标从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
",ans);
29 }
30 return 0;
31 }