参考:https://blog.csdn.net/qq_30241305/article/details/50700199
A.更正后模板代码,求子串最初出现位置
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 using namespace std;
5 int nexta[10005],a[1000005],s[10005];
6 int n,m;
7 void getnexta(int s[])//初始next数组
8 {
9 memset(nexta,0,sizeof(nexta));
10 int k = -1,j = 0;
11 nexta[0] = -1;
12
13 while(j <m)//这里的m为全局变量,为模式串长度
14 {
15
16 if(k == -1 || s[k] == s[j])
17 {
18 nexta[j + 1] = k + 1;
19 j ++;
20 k ++;
21 }
22 else
23 {
24 k = nexta[k];
25 }
26 }
27
28 }
29 int kmp(int s[],int t[])//t模式串,s母串
30 {
31 getnexta(t);
32
33 int i = 0,j = 0;
34 while(i < n && j < m)
35 {
36 if(j == -1 || s[i] == t[j])
37 {
38 i ++;
39 j ++;
40 }
41 else
42 {
43 j = nexta[j];
44 }
45 if(j == m)
46 {
47 return i - j+ 1;//匹配开始位置
48 }
49 }
50 return -1;
51 }
52 int main()
53 {
54 // freopen("in.txt","r",stdin);
55 int T;
56 scanf("%d",&T);
57 while(T--)
58 {
59 scanf("%d%d",&n,&m);
60 for(int i = 0;i < n; i ++)
61 {
62 scanf("%d",&a[i]);
63 }
64 for(int j = 0; j < m;j ++)
65 {
66 scanf("%d",&s[j]);
67 }
68 printf("%d\n",kmp(a,s));
69 }
70 return 0;
71 }
B.较好的模板,求字串出现次数,可重叠
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 using namespace std;
5 int nexta[1000006];
6 char t[1000006],s[1000006];
7 void getnexta(char s[])
8 {
9 memset(nexta,0,sizeof(nexta));
10 int n = strlen(s);//这里的s并非为母串,而要看传入的数组!
11 int k = -1,j = 0;
12 nexta[0] = -1;
13 while(j <n)
14 {
15
16 if(k == -1 || s[k] == s[j])
17 {
18 nexta[j + 1] = k + 1;
19 j ++;
20 k ++;
21 }
22 else
23 {
24 k = nexta[k];
25 }
26 }
27
28 }
29 int kmp(char s[],char t[])//t模式串,s母串.
30 {
31 getnexta(t);
32 int ans = 0;
33 int n = strlen(s),m = strlen(t);
34 int i = 0,j = 0;
35 while(i < n && j < m)
36 {
37 if(j == -1 || s[i] == t[j])
38 {
39 i ++;
40 j ++;
41 }
42 else
43 {
44 j = nexta[j];
45 }
46 if(j == m)//根据题目要求改变
47 {
48 ans ++;
49 j = nexta[j];
50 }
51 }
52 return ans;
53 }
54 int main()
55 {
56 // freopen("in.txt","r",stdin);
57 int T;
58 scanf("%d",&T);
59 while(T--)
60 {
61 scanf("%s%s",t,s);
62 printf("%d\n",kmp(s,t));
63 }
64 return 0;
65 }
C。不能重叠
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 using namespace std;
5 int nexta[1006];
6 char t[1006],s[1006];
7 void getnexta(char s[])
8 {
9 memset(nexta,0,sizeof(nexta));
10 int n = strlen(s);
11 int k = -1,j = 0;
12 nexta[0] = -1;
13 while(j < n )
14 {
15
16 if(k == -1 || s[k] == s[j])
17 {
18 nexta[j + 1] = k + 1;
19 j ++;
20 k ++;
21 }
22 else
23 {
24 k = nexta[k];
25 }
26 }
27
28 }
29 int kmp(char s[],char t[])//t模式串,s母串.
30 {
31 getnexta(t);
32 int ans = 0;
33 int n = strlen(s),m = strlen(t);
34 int i = 0,j = 0;
35 while(i < n && j < m)
36 {
37 if(j == -1 || s[i] == t[j])
38 {
39 i ++;
40 j ++;
41 }
42 else
43 {
44 j = nexta[j];
45 }
46 if(j == m)//根据题目要求改变
47 {
48 ans ++;
49 j = 0;
50 }
51 }
52 return ans;
53 }
54 int main()
55 {
56 // freopen("in.txt","r",stdin);
57 while(1)
58 {
59 scanf("%s",s);
60 if(strcmp(s,"#") == 0)
61 break;
62 scanf("%s",t);
63 printf("%d\n",kmp(s,t));
64 }
65 return 0;
66 }
D。最小循环节
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 using namespace std;
5 int nexta[100005];
6 char s[100005];
7 void getnexta(char s[])
8 {
9 memset(nexta,0,sizeof(nexta));
10 int n = strlen(s);
11 int k = -1,j = 0;
12 nexta[0] = -1;
13 while(j < n )
14 {
15 if(k == -1 || s[k] == s[j])
16 {
17 nexta[j + 1] = k + 1;
18 j ++;
19 k ++;
20 }
21 else
22 {
23 k = nexta[k];
24 }
25 }
26 }
27 int main()
28 {
29 // freopen("in.txt","r",stdin);
30 int T,ans,n,temp;
31 scanf("%d",&T);
32 while(T --)
33 {
34 scanf("%s",s);
35 n = strlen(s);
36 getnexta(s);
37 temp = n - nexta[n];//最小循环节,例如s:abcdeabc,则串长n为8,nexta[n]为s[0]到s[7]的
38 if(temp == n)//前,后缀匹配长度为3(abc),所以n-next[n]为8-3=5,即最小循环节长(abcde)
39 {
40 ans = n;//除nexta[0]为-1外,其余nexta值最小为0,此情况为整体字符串为一个循环节
41 }
42 else if(n % temp == 0)//自身已经循环
43 {
44 ans = 0;
45 }
46 else
47 {
48 ans = temp - (n % temp);
49 }
50 printf("%d\n",ans);
51 }
52 return 0;
53 }
G.
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 using namespace std;
5 int nexta[1000002];
6 char s[1000002];
7 int n;
8 void getnexta()
9 {
10 memset(nexta,0,sizeof(nexta));
11 int k = -1,j = 0;
12 nexta[0] = -1;
13 while(j < n )
14 {
15
16 if(k == -1 || s[k] == s[j])
17 {
18 nexta[j + 1] = k + 1;
19 j ++;
20 k ++;
21 }
22 else
23 {
24 k = nexta[k];
25 }
26 }
27
28 }
29 int main()
30 {
31 //freopen("in.txt","r",stdin);
32 int ans;
33 while(1)
34 {
35 ans = 0;
36 scanf("%s",s);
37 if(strcmp(s,".") == 0)
38 break;
39 n = strlen(s);
40 getnexta();
41 if(n % (n - nexta[n]) == 0 )//记住n-nexta[n]为最小循环节长度
42 ans = n / (n - nexta[n]);
43 else
44 ans = 1;
45 printf("%d\n",ans);
46 }
47 return 0;
48 }
49
50
51 //ababa
H。题意:https://blog.csdn.net/alongela/article/details/8196915
1 #include <iostream>
2 #include <cstdio>
3 #include <cstring>
4 using namespace std;
5 int nexta[1000002];
6 char s[1000002];
7 int ans[1000002];
8 int n;
9 void getnexta()
10 {
11 memset(nexta,0,sizeof(nexta));
12 int k = -1,j = 0;
13 nexta[0] = -1;
14 while(j < n )
15 {
16
17 if(k == -1 || s[k] == s[j])
18 {
19 nexta[j + 1] = k + 1;
20 j ++;
21 k ++;
22 }
23 else
24 {
25 k = nexta[k];
26 }
27 }
28
29 }
30
31 int main()
32 {
33 //freopen("in.txt","r",stdin);
34 int temp,k;
35 while(scanf("%s",s) != EOF)
36 {
37 k = 0;
38 n = strlen(s);
39 getnexta();
40 temp = n;
41 ans[k] = n;
42 k ++;
43 while(nexta[temp]!= 0)//当nexta[temp]==0说明该字符前的串没有相同前后缀
44 {
45 temp = nexta[temp];
46 ans[k] = temp;
47 k ++;
48 }
49 for(int i = k -1; i > 0; i --)
50 printf("%d ",ans[i]);
51 printf("%d\n",ans[0]);
52
53 }
54 return 0;
55 }
56
57
58 //ababa
来源:https://www.cnblogs.com/hemeiwolong/p/9503903.html