带你学字符串匹配算法之KMP

带你学字符串匹配算法之KMP

前言

我也是偶尔刷知乎时看到了这个字符串匹配算法,感觉还是很棒的,也算是一边写博客,一边学习,如有不足之处还请指正。

第一种理解方法

看到这里是不是慌了一下?刚刚我去csdn转了一圈,了解到有两种理解方法,可能第一种比较好理解一点。
首先给出待匹配字符串"BBC ABCDAB ABCDABCDABDE",然后我们的子串是"ABCDABD",现在开始。首先拿出一个部分匹配表出来。部分匹配表是针对待匹配字符串而言的,一言以蔽之,即:当前字符串的前缀与后缀完全相同时的最大长度。前缀指的是除了最后一个字符外剩下的部分的组合,如ABC的前缀可以是A,也可以是AB;同理,ABC的后缀是BC或者是C。
OK那么带匹配字符串的部分匹配表是:
0,1,0,0,1,…
有没有什么快速的方法可以求这个表呢?有的,而且还很好理解:(转自https://www.cnblogs.com/c-cloud/p/3224788.html)

void makeNext(const char P[],int next[])
{
    int q,k;//q:模版字符串下标;k:最大前后缀长度
    int m = strlen(P);//模版字符串长度
    next[0] = 0;//模版字符串的第一个字符的最大前后缀长度为0
    for (q = 1,k = 0; q < m; ++q)//for循环,从第二个字符开始,依次计算每一个字符对应的next值
    {
        while(k > 0 && P[q] != P[k])//递归的求出P[0]···P[q]的最大的相同的前后缀长度k
            k = next[k-1];          //不理解没关系看下面的分析,这个while循环是整段代码的精髓所在,确实不好理解
        if (P[q] == P[k])//如果相等,那么最大相同前后缀长度加1
        {
            k++;
        }
        next[q] = k;
    }
}

我真的觉得这个算法非常牛逼,以至于我要画个图,妙啊:
在这里插入图片描述
OK搞定了这个数组,那么剩下的就很简单了。
当做字符串匹配时,如果某个字符匹配成功,则匹配成功计数值succ+=1,同时开始匹配下一个字符。
如果匹配某个字符失败(位置是index),则开始匹配的位置向前移动x,其中x = succ - next[index-1]。
代码我就不放了,真的没啥好放的了。
代码我借用了csdn@Summit_Yue,侵删

#include<iostream>
#include<algorithm>
#include<string>

using namespace std;

void ComputePrefix(string s,int next[]){
    int n = s.length();
    int q,k;
    next[0] = 0;
    for(k=0,q=1;q<n;q++){
        while(k>0 && s[k]!=s[q])
            k = next[k];
        if(s[k]==s[q])
            k++;
        next[q] = k;
    }
}
void KMPMatcher(string text,string pattern) {
    int n = text.length();
    int m = pattern.length();
    int next[pattern.length()];
    ComputePrefix(pattern, next);

    for(int i=0,q=0;i<n;i++) {
        while(q>0 && pattern[q]!=text[i])
            q = next[q];
        if(pattern[q]==text[i])
            q++;
        if(q==m)
        {
            cout<<"Pattern occurs with shift "<<i-m+1<<endl;
            q=0;
        }
    }
}

int main()
{
    string s = "abcdabcdebcd";
    string p  ="bcd";
    KMPMatcher(s, p);
    cout<<endl;
    return 0;
}
原文链接:https://blog.csdn.net/u011197534/article/details/78385547

第二种理解方法

第二种理解方法是我看到知乎上一位老哥写的,他的理解角度是,状态机。然后他没有用next数组,而是用256*sizeof(pat)做的,我目测写的还算不错,这里我就只贴链接了(反正我是没打算实现)
点这里
这个算法我觉得角度很棒。

猜你喜欢

转载自blog.csdn.net/weixin_44039270/article/details/106606417
今日推荐