kmp-模板-hd-1711

p数组记录的是当该位置上失配的时候,跳到第几个进行继续匹配;
 1 /*
 2    题意:给两个数串,求模板串第一此出现在源串中的位置,开头的位置;没有输出-1;
 3    算法:kmp
 4    先对字符串进行自匹配;
 5    然后串间匹配;
 6  */
 7 #include<iostream>
 8 #include<cstdio>
 9 #include<cstring>
10 #include<string>
11 using namespace std;
12 int s[1000005],t[10005],p[10005];//s是源串,t是模板串,p是自匹配数组(next);
13 int n,m;
14 int kmp()//模板;
15 {
16     int ans=0;
17     p[0]=p[1]=0;
18     //p数组是错位排列的,p[i]表示的是p[i-1]的信息;即到目前为止的最长前缀;
19     for(int i=1;i<m;i++)
20     {
21         int j=p[i];
22         while(j&&t[i]!=t[j])
23         {
24             j=p[j];//定位j的位置;
25         }
26         p[i+1]=t[i]==t[j]?j+1:0;
27     }
28     int j=0,temp=0;
29     for(int i=0;i<n;i++)
30     {
31         while(j&&s[i]!=t[j])
32         {
33             j=p[j];
34         }
35         if(s[i]==t[j])
36             j++;
37         if(j==m)
38             return i+1-m+1;
39     }
40     return 0;
41     //可以判断是否有子串,也可以计算有多少子串;
42 }
43 int main()
44 {
45     int T;
46     scanf("%d",&T);
47     while(T--)
48     {
49         memset(s,0,sizeof(s));
50         memset(t,0,sizeof(t));
51         scanf("%d%d",&n,&m);
52         for(int i=0;i<n;i++)
53             scanf("%d",&s[i]);
54         for(int i=0;i<m;i++)
55         {
56             scanf("%d",&t[i]);
57         }
58         int ans=kmp();
59         if(ans==0)
60             printf("-1
");
61         else
62             printf("%d
",ans);
63     }
64     return 0;
65 }
View Code

 下面是自己按照俞勇的书敲的模板;比较详细一点,理解更深了一点;

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<string>
 5 using namespace std;
 6 string s,pattern;
 7 int next[10100]={0};
 8 int n,m;
 9 int position[100000]={0};//标记每一个字串的起始位置;
10 void kmp()
11 {
12     for(int i=1;i<n;i++)
13     {
14         int j=i;
15         while(j>0)
16         {
17             j=next[j];
18             if(pattern[j]==pattern[i])
19             {
20                 next[i+1]=j+1;
21                 break;
22             }
23         }
24     }
25     for(int i=0,j=0;i<m;i++)
26     {
27         //i标记的是大串上的位置,j标记的是小串上的位置;
28         if(j<n&&s[i]==pattern[j])
29             j++;
30         else
31         {
32         //    如果失配j就跳到小串的下一个位置继续匹配;
33             while(j>0)//j等于0就是没有继续可跳的位置;
34             {
35                 j=next[j];
36                 if(s[i]==pattern[j])
37                 {
38                     j++;
39                     break;
40                 }
41             }
42         }
43         if(j==n)
44             cout<<i-n+1+1<<endl;//返回起始位置(i-n+1)是数组中的位置,再加1是从一开始的位置定位;
45     }
46     //没有子串,在这里可以返回-1;
47 }
48 int main()
49 {
50     cin>>s>>pattern;
51     n=pattern.size();
52     m=s.size();
53     kmp();
54     return 0;
55 }
View Code
原文地址:https://www.cnblogs.com/by-1075324834/p/4514633.html