KMP模板

参考: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

 

posted @ 2018-08-20 09:53  hemeiwolong  阅读(116)  评论(0编辑  收藏  举报