KMP算法

为了解决字符串匹配问题

给你两个字符串,寻找其中一个字符串是否包含另一个字符串,如果包含,返回包含的起始位置。

 1 //str为子串
 2 //prt为母串
 3 
 4 
 5 void cal_next(char *str, int *next, int len)
 6 {
 7     next[0] = -1;//next[0]初始化为-1,-1表示不存在相同的最大前缀和最大后缀
 8     int k = -1;//k初始化为-1
 9     for (int q = 1; q <= len-1; q++)
10     {
11         while (k > -1 && str[k + 1] != str[q])//如果下一个不同,那么k就变成next[k],注意next[k]是小于k的,无论k取任何值。
12         {
13             k = next[k];//往前回溯
14         }
15         if (str[k + 1] == str[q])//如果相同,k++
16         {
17             k = k + 1;
18         }
19         next[q] = k;//这个是把算的k的值(就是相同的最大前缀和最大后缀长)赋给next[q]
20     }
21 }
22 
23 int KMP(char *str, int slen, char *ptr, int plen)
24 {
25     int *next = new int[plen];
26     cal_next(ptr, next, plen);//计算next数组
27     int k = -1;
28     for (int i = 0; i < slen; i++)
29     {
30         while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配)
31             k = next[k];//往前回溯
32         if (ptr[k + 1] == str[i])
33             k = k + 1;
34         if (k == plen-1)//说明k移动到ptr的最末端
35         {
36             //cout << "在位置" << i-plen+1<< endl;
37             //k = -1;//重新初始化,寻找下一个
38             //i = i - plen + 1;//i定位到该位置,外层for循环i++可以继续找下一个(这里默认存在两个匹配字符串可以部分重叠),感谢评论中同学指出错误。
39             return i-plen+1;//返回相应的位置
40         }
41     }
42     return -1;  
43 }

 

 

模板:

 1 #include<stdio.h>
 2 #include<string.h>
 3 void makeNext(const char P[],int next[])
 4 {
 5     int q,k;
 6     int m = strlen(P);
 7     next[0] = 0;
 8     for (q = 1,k = 0; q < m; ++q)
 9     {
10         while(k > 0 && P[q] != P[k])
11             k = next[k-1];
12         if (P[q] == P[k])
13         {
14             k++;
15         }
16         next[q] = k;
17     }
18 }
19 
20 int kmp(const char T[],const char P[],int next[])
21 {
22     int n,m;
23     int i,q;
24     n = strlen(T);
25     m = strlen(P);
26     makeNext(P,next);
27     for (i = 0,q = 0; i < n; ++i)
28     {
29         while(q > 0 && P[q] != T[i])
30             q = next[q-1];
31         if (P[q] == T[i])
32         {
33             q++;
34         }
35         if (q == m)
36         {
37             printf("Pattern occurs with shift:%d\n",(i-m+1));
38         }
39     }    
40 }
41 
42 int main()
43 {
44     int i;
45     int next[20]={0};
46     char T[] = "ababxbababcadfdsss";
47     char P[] = "abcdabd";
48     printf("%s\n",T);
49     printf("%s\n",P );
50     // makeNext(P,next);
51     kmp(T,P,next);
52     for (i = 0; i < strlen(P); ++i)
53     {
54         printf("%d ",next[i]);
55     }
56     printf("\n");
57 
58     return 0;
59 }

 KMP求子串出现的次数

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int MAXW=10001,MAXT=1000001;
 6 char W[MAXW],T[MAXT];
 7 int next[MAXW];
 8 int lenW,lenT;
 9 
10 void getnext(int lenW)
11 {
12     int i=0,j=-1;
13     next[i]=-1;
14     while(i<lenW) {
15         if(j==-1||W[i]==W[j]) {
16             next[++i]=++j;
17         }
18         else j=next[j];
19     }
20 }
21 
22 int kmp(int pos,int lenW,int lenT)
23 {
24     int i=pos,j=0,ans=0;
25     while(i<lenT) {
26         if(T[i]==W[j]||j==-1) ++i,++j;
27         else j=next[j];
28         if(j==lenW) {
29             ans++;
30             j=next[j-1];
31             i--;
32         }
33     }
34     return ans;
35 }
36 
37 
38 int main()
39 {
40     int n;
41     scanf("%d",&n);
42     while(n--) {
43         scanf("%s%s",W,T);
44         lenW=strlen(W);
45         lenT=strlen(T);
46         getnext(lenW);
47         printf("%d\n",kmp(0,lenW,lenT));
48     }
49     return 0;
50 }

 

posted @ 2018-04-19 21:14  ouyang_wsgwz  阅读(131)  评论(0编辑  收藏  举报