KMP

介绍

1
KMP算法有几种表达方法,这里是,next[i]表示0~i-1的前后缀匹配情况(第i位不参与)。
4
Next 数组的递推关系
5
所以这里的next数组有以下特征:

  • next[0]=-1(规定)
  • next[1]=0,因为匹配时不包含p[1],则只有p[0]参与匹配,规定一个数字匹配结果为0(不包含字符串本身);
  • 匹配的过程中不断进行k=next[k],只有当k=-1时,才表示无法找到可以匹配的前后缀,此时next[j+1]=0,因为要比较next[j]?=next[k],所以k=0时也是在比较。

2
从图中可以看出,此时,K=0,J=3,我们比较p[0]与p[3]是为了计算p[4],因为p[0]=p[3],所以p[4]=p[3]+1=1;
2
此时,k=1,j=4,因为p[1]=p[4],所以p[5]=p[4]+1=2;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void GetNext(int* next, char* p)
{

int len=strlen(p);
next[0]=-1;//第一个位置一直都是-1
int k=-1;//k=-1表示未找到可以匹配的
int j=0;//因为next[0]固定为-1,所以从next[1]开始计算
//next[j+1]由next[j]推导而来,所以j从0开始
while(j<len-1)//j到len-2即可,就可以推出next[len-1]
{
if(k==-1||p[j]==p[k])//一开始k=-1,next[1]=-1+1=0
//计算next[j=2]时,比较p[1]与p[0],如果不相等,则k=next[0]=-1,不匹配,next[2]=0
{
next[j+1]=k+1;
j++;
k++;
}
else
{
k=next[k];
}
}
}

完整的KMP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include<stdio.h>
#include<string>
#include<string.h>
#include<iostream>
#include<stack>
using namespace std;
int next[100];
void GetNext(int* next, char* p)
{

int len=strlen(p);
next[0]=-1;//第一个位置一直都是-1
int k=-1;//k=-1表示未找到可以匹配的
int j=0;//因为next[0]固定为-1,所以从next[1]开始计算
//next[j+1]由next[j]推导而来,所以j从0开始
while(j<len-1)//j到len-2即可,就可以推出next[len-1]
{
if(k==-1||p[j]==p[k])//一开始k=-1,next[1]=-1+1=0
//计算next[j=2]时,比较p[1]与p[0],如果不相等,则k=next[0]=-1,不匹配,next[2]=0
{
next[j+1]=k+1;
j++;
k++;
}
else
{
k=next[k];
}
}
}
int KMP(char* str1, char*str2)
{

int flag=-1;
int len1=strlen(str1);
int len2=strlen(str2);
int i=0;
int j=0;
while(i<len1)
{
if(str1[i]==str2[j]||j==-1)//在相等的时候,i++,j++;没有匹配的前缀时,i++,j=0匹配串从头开始
//即最坏的情况下,和暴力法一样,即不匹配的时候,i++,j=0
{
i++;
j++;
}
else
{
j=next[j];//这儿和暴力法不一样
}
if(j==len2)
{
flag=i-len2;
break;
}
}
return flag;
}

int main()
{

char str1[100];
char str2[100];
while(scanf("%s%s",str1,str2)!=EOF)
{
GetNext(next,str2);
int len1=strlen(str1);
int len2=strlen(str2);
int flag= KMP(str1,str2);
if(flag!=-1)
printf("YES %d\n",flag);
else
printf("NO\n");
}
return 0;
}