【介绍】
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。
【思想】
对于给定的两个串A,B,长度分别为N,M让你查找B串在A串中的位置。
对于这么一个问题,我们首先的想法就是O(MN)的暴力枚举,但是假设M和N都大于10^6,那么就有可能扛不住了,这时候KMP就派上了用场。
设p为目前枚举到A串的位置,q为目前枚举B串的位置。
假设A串为abacabbc,B串为acab。
KMP的核心思想就是对B串进行自身匹配,节省了之后在A串中查找的时间,定义prefix数组记录自身匹配到的位置,如下:
acab
0010
自身匹配结束后,就可以在A串中查找了。
abacabbc
acab
p=1 q=1
abacabbc
acab
p=3 q=1
abacabbc
acab
p=6 q=4
匹配成功
再举个特殊例子:
比如说A串是zzkorzzzkzzk,B串是zzkzzk
自身匹配就是:
zzkzzk
010123
特殊的地方就是这种情况:
zzkorzzzkzzk
zzkzzk
当p=8,q=2时,因为Ap!=Bq+1所以将q=prefix[q]相当于将B串向后移了一位。
如下:
zzkorzzzkzzk
zzkzzk
此时p=8,q=1
【核心代码】
B串自身匹配:
void Getprefix(const char *a)//自身匹配,构造prefix数组。
{
int k=0,len=strlen(a+1); prefix[0]=prefix[1]=0;
for (int i=2; i<=len; i++)
{
while (k>0&&a[k+1]!=a[i]) k=prefix[k];
if (a[k+1]==a[i]) k++;
prefix[i]=k;
}
}
在A串中查找B串的位置:
void KMP(const char *a,const char *b)//在A串中查找B串的位置
{
int k=0,Alen=strlen(a+1),Blen=strlen(b+1);
for (int i=1; i<=Alen; i++)
{
while (k&&b[k+1]!=a[i]) k=prefix[k];
if (b[k+1]==a[i]) k++;
if (k==Blen) {printf("%d",i-Blen+1); return;}
}
printf("-1");
}