算法学习-KMP(字符串匹配)解释

KMP算法

BF算法

BF算法就是我们最基本的求解字符串匹配的算法,算法的时间复杂度为O(M*N),空间复杂度为O(1),具体过程如下:

第一次 第二次 第三次 第四次
模式串S[i] abcababc abcababc abcababc abcababc
匹配串T[j] ababc ababc ababc ababc

可以看到在第三次匹配失败的时候,我们要回溯,直接S串直接i+=1,然后T串j=0从头继续开始。这样复杂度就比较高了。

KMP算法

而KMP算法就是为了解决BF算法的复杂度比较高而出现的,KMP算法的时间复杂度为O(M+N),空间复杂度为O(N),具体过程如下:

第一次 第二次 第三次 第四次
模式串S[i] abaababc abaababc abaababc abaababc
匹配串T[j] ababc ababc ababc ababc
第四次 第五次 第六次 第七次 第八次
abaababc abaababc abcababc abcababc abcababc
ababc ababc ababc ababc ababc

在第四次匹配失败后,不进行回溯,而是直接对匹配串进行下一个匹配,是因为前面已经把aba匹配过了,知道前一个也是a不需要再次进行匹配,这个就是通常所说的KMP算法。而在匹配失败后到底对哪个进行再次匹配,也就需要我们求next[j]数组了。

求next数组

next数组存放的是,当匹配失败后,需要跳转到哪个字符再次进行匹配。
求的方法,手算:
例子(ababc)的next数组为:[-1 0 0 1 2].


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


next[2] = next[1+1];
next[1] = 0
T[1] != T[0];
则next[2] = next[1] = 0;


next[3] = next[2+1];
next[2] = 0;
T[2] == T[0] (T[2] = a, T[1] = b)
则next[3] = next[2]+1;


next[4] = next[3+1];
next[3] = 1;
T[3] == T[1];
则next[4] = next[3]+1 = 2;

以上是手算的解法,代码求解比较简单。
如下

代码已经改在最下面

改进后的next数组

改进的之后的next数组效率更高,但是我暂时还没找到如何手算,假如你知道,请评论给我,非常感谢。但是代码实现非常简单,就是在第一次判断之后,再进行一次判断。
代码如下:

此段代码已经删除请参考下面代码


KMP代码实现

而KMP整个的代码实现如下:

请参考博客下面代码


更新时间:2016年5月5日凌晨2点09分


新版本

今天遇到一个KMP的题目,原来发现自己的代码写的很乱,并且适用性非常低,这里放上更好的新版本代码:

首先:
计算过程是没有变化的:

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #ffffff}span.s1 {font-variant-ligatures: no-common-ligatures; color: #de38a6}span.s2 {font-variant-ligatures: no-common-ligatures}span.s3 {font-variant-ligatures: no-common-ligatures; color: #00b1ff}span.s4 {font-variant-ligatures: no-common-ligatures; color: #8b87ff}

void getNext(string W, int next[]){
    memset(next, 0, sizeof(int)*(int)(W.length()+1));
    for(int i=1; i<(int)W.length(); i++){
        int j=i;
        while(j>0){
            j=next[j];
            if(W[j]==W[i]){
                next[i+1]=j+1;
                break;
            }
        }
    }
}
//  这个版本的代码才是我上面手写计算的思想

KMP完整实现

当然对应的KMP版本的代码需要进行一些调整:

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #ffffff}span.s1 {font-variant-ligatures: no-common-ligatures; color: #de38a6}span.s2 {font-variant-ligatures: no-common-ligatures}span.s3 {font-variant-ligatures: no-common-ligatures; color: #00b1ff}span.s4 {font-variant-ligatures: no-common-ligatures; color: #8b87ff}

int KMP_(const char *src, const char *tar, int *next){
    int srcLength = (int)strlen(src);
    int tarLength = (int)strlen(tar);
    int i = 0, j = 0;
    while (i < srcLength) {
        if (src[i] == tar[j]) {
            i++;
            j++;
        }else{
            while (j != 0 && src[i] != tar[j]) {
                j = next[j];
            }
            i++;
        }
        if (j == tarLength) {
            return i-j;
        }
    }
    return -1;
}
//这个是成功之后,返回匹配的位置。

当然有的要求返回匹配的次数,代码只是大同小异,只是在j == length的时候不要急着返回就好了。

代码入下:

p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Menlo; color: #ffffff}span.s1 {font-variant-ligatures: no-common-ligatures; color: #de38a6}span.s2 {font-variant-ligatures: no-common-ligatures}span.s3 {font-variant-ligatures: no-common-ligatures; color: #00b1ff}span.s4 {font-variant-ligatures: no-common-ligatures; color: #8b87ff}

int KMP(string str1, string str2, int next[]){
    int len1 = (int)str1.length();
    int len2 = (int)str2.length();
    if(len1 > len2) return 0;
    int i = 0, j = 0;
    int count = 0;
    while(i < len2){
        if(j < len1 && str1[j] == str2[i]){
            j++;
            i++;
        }else{
            while (j > 0 && str1[j] != str2[i]) {
                j = next[j];
            }
        }
        if(j >= len1){
            count++;
        }
    }
    return count;
}//此代码是返回匹配次数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值