KMP算法求解串的模式匹配

测试样例
this is a simple text
simplep
大致思路:暴力求解进行了大量无关紧要的比较,kmp使得只有遍历一边串就可以得出结果,算法核心思想是,为串和模式分别设置两个指针i,j,都从头开始扫描,如果字符可以匹配,两指针都前进,问题主要在如果匹配失败的处理上,kmp不会让i回溯,只会让j回退(回退需要用到next数组,next数组的求法参考算法浙江大学mooc视频,结合视频更容易理解)到前缀和后缀相同的最大的前缀下标处,然后看j+1处的字符可否与i处的字符匹配,如果可以则二指针同时++,如果不可以继续回退j指针,直到j指针指向了-1(表明模式又要重头开始与串匹配),这样当i遍历完或者j指向模式末尾下标则函数结束
算法优的关键所在:字符匹配失败时,i指针(指向串)不回溯,而是可以继续向前扫描
为什么可以不回溯,发现一个奇妙的现象,
串:abcdabc…
模式:abcdabd
当前i指向e,j指向d,二者不匹配
则现在将j指向下标2(next[j-1]为2),即c,发现匹配了,i,j继续前进

#include<cstdio>
#include<string>
#include<iostream>
#include<vector>
using namespace std;
string text,s;
#define maxn 100
int match[maxn];
void getmatch()
{
    
    
    int n=s.size();
    match[0]=-1;
    int j=-1;
    for(int i=1;i<n;i++){
    
    
        while(j!=-1&&s[i]!=s[j+1]){
    
    
            j=match[j];
        }
        if(s[i]==s[j+1]){
    
    
            j++;
        }
        match[i]=j;
    }
}
int KMP()
{
    
    
    int j=-1;
    for(int i=0;i<text.size();i++){
    
    
        while(j!=-1&&text[i]!=s[j+1]){
    
    
            j=match[j];
        }
        if(text[i]==s[j+1]){
    
    
            j++;
        }
        if(j==s.size()-1){
    
    
            return i-s.size()+1;
        }
    }
    return -1;
}
int main()
{
    
    
    getline(cin,text);
    getline(cin,s);
    getmatch();
    //for(int i=0;i<s.size();i++){
    
    
    //    printf("%d ",match[i]);
    //}
    printf("%d\n",KMP());
}

猜你喜欢

转载自blog.csdn.net/weixin_45890608/article/details/113759102