kmp匹配算法

来源:互联网 发布:魏则西的回答 知乎 编辑:程序博客网 时间:2024/05/17 07:40

在讲解kmp算法之前,先讨论下一般的模式匹配算法

先看下代码

int index(string s,string t,int pos){for (int i=pos;i<s.length()&&i+t.length()<=s.length();i++){int flag=1;for (int j=0;j<t.length();j++){if (s[i+j]!=t[j]){flag=0;break;}}if (flag){return i+1;}}return 0;}

返回的是b串第一次在a串的pos位置后出现的位置

可以显而意见的是复杂度为O(n*m)

在a串和b串为如下的形式的时候时

a:0000000001

b:001

你会发现b串在a串中进行匹配的时候,要到最后一次才会匹配成功,而前面的匹配很多都做了无用功,i指针根本就没必要回朔


kmp算法

kmp算法巧妙的解决了这个问题

将问题的复杂度下降到O(n+m)

那么它是怎么实现的呢?

先给大家看几个图示


当a串与b串进行比较的时候,可能在分别在i和j的位置的时候匹配失败了

这个时候如果是一般匹配方法就会i指针回朔到b1+1位置,而j则会回朔到b2位置

但是如果仔细观察下你会发现(b1,i-1)和(b2,j-1)是完全匹配的,而且你也可能会发现可能在b串中本身就存在(b2,s)完全等于(k,j-1)的情况,那么这个时候何不直接把j回朔到s+1的位置呢?

如下图所示



这样算法复杂度就可以得到很好的优化

但是如何实现以上过程呢

这里引进next数组

next[i]:=如果匹配失败了j指针应该滑向的位置

也可以理解成最大的一个值使得对于b串而言(0,next[i]-1)完全等于(j-next[i],j-1)

则可以定义如下

next[i]=-1,i==0

next[i]=k,,0<k<j,其中"p0p1p2p3...pk-1"="pj-kpj-k+1pj-k+2...pj-1"

next[i]=0,其余的情况,其实也就是b串0到j-1的位置上没有前后相互匹配的情况


那么只要求出next数组的值,就万事大吉了

下面给出代码

void getNext(char *p,int *next){    int j,k;    next[0]=-1;    j=0;    k=-1;    while(j<strlen(p)-1)    {        if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k]        {            j++;            k++;            next[j]=k;        }        else                   //p[j]!=p[k]            k=next[k];    }}int KMPMatch(char *s,char *p)    //如果不存在匹配项,则返回-1,否在返回开始的匹配位置{                                //p匹配到s,s必须比p长    int next[100];    int i,j;    i=0;    j=0;    getNext(p,next);    while(i<strlen(s))    {        if(j==-1||s[i]==p[j])        {            i++;            j++;        }        else        {            j=next[j];       //消除了指针i的回溯        }        if(j==strlen(p))            return i-strlen(p);    }    return -1;}

写法二,思路都是一样的,只是代码习惯的不同。。

#include <bits/stdc++.h>using namespace std;#define maxn 105int next[maxn];void get_next(string b){next[0]=-1;int j=0;for (int i=1;i<b.length();i++){while(j>0&&b[i]!=b[j]) j=next[j];if (b[i]==b[j]) next[i]=j++;}}int kmp(string a,string b,int pos){memset(next,0,sizeof(next));get_next(b);int j=0;for (int i=pos;i<a.length();i++){while(j>0&&a[i]!=b[j]) j=next[j];if (a[i]==b[j]) j++;if (j==b.length()){return i-b.length()+1;}}return -1;}int main(){string a,b;while(cin>>a>>b){printf("%d\n",kmp(a,b,0));}return 0;}


0 0
原创粉丝点击