您的位置:首页 > 其它

字符串匹配问题——KMP算法

2017-02-15 23:00 253 查看
KMP算法

KMP是解字符串匹配这类题目的算法,又称“看毛片”算法。

如下图,给定一个长度为n的文本,给定一个长度为m 的字符串,求该字符串在给定文本的中出现的次数。KMP就是解决这一类题目的。

i 1

zzkzzzkzzzkzkkkz

zzkzzkzzkzzk

j 1

继续考虑上面的问题。首先我相信每个人都有一个笨蛋的想法,就是枚举在文本的起始位置i,然后把字符串从这个位置开始一个一个对比,如果遇到某一位j不相同就停止并i++,重新开始对比。这样的效率最坏的情况为O(m(n-1)),很不优秀。KMP其实就是基于这个笨蛋思想的优化。

i 6

a zzkzzzkzzzkzkkkz

b zzkzzkzzkzzk

j 5

我们可以假设当前对比文本位置i,字符串已经比较了j位,如果i和j+1不同其实我们不需要重新开始匹配,如果基于原来的基础之上,稍微将字符串往后移一移,这样j可以保留一定的位置,效率上得到提升。但是新位置还是要满足匹配,所以就要寻找一个最大的j’满足b[1..j’]和 a[i-j’+1..i]一致,然后继续用j’+1和i进行比较,如果不满足就继续进行以上过程。基本过程如下。

i 6

a zzkzzzkzzzkzkkkz

b zzkzzkzzkzzk

j 2 //2是能满足的最大j’,但是j’+1与i不匹配,所以继续

i 6

a zzkzzzkzzzkzkkkz

b zzkzzkzzkzzk

j 0

因为j之前已经匹配,所以寻找b[1..j’]和 a[i-j’+1..i]一致,其实就是寻找一段满足b[1..j’]和 b[j-j’+1..j]一致的自匹配,这个明显能够预处理出来,效率为O(n+m)。

主程序如下:

void KMP(){
int j=0;
for (int i=1;i<=n;i++){
while (j>0&&b[j+1]!=a[i]) j=f[j];  //f[j]就是预处理的数组,存最大的j’
if (b[j+1]==a[i]) j++;
if (j==m) printf("%d\n",i-m+1),j=f[j];   //完成匹配,输出
}
}


预处理f数组的过程与寻找匹配差不多,代码如下:

void work(){
int j=0;
for (int i=2;i<=m;i++){  //这里一定要从2开始,因为从1开始就全部匹配了,f[j]不能满足小于j
while (j>0&&b[j+1]!=b[i]) j=f[j];
if (b[j+1]==b[i]) j++;
f[i]=j;
}
}


KMP差不多就是这样,但是KMP存在有缺陷,一次只能拿一个字符串与文本比较,所以就有了AC自动机。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: