KMP算法详解

KMP匹配实际上就是在一般匹配的过程中,有没有已经匹配好的了,现场去找又太麻烦所以有了KMP

KMP数组的产生就是自己匹配自己,因为一个字符串能否接续上就是看前缀和后缀有没有重合的部分,例如:

EBDAE 这个字符串可以用 KMP 来加快匹配,因为这个字符串有这E这个共同的前缀和后缀,所以有下一个例子:

EBDAEBDAE

这个例子中,两个EBDAE叠在了一起,所以在找到第二个EBDAE时,不用重新去找,只需要在第二个E接续上就可以了。

下面是匹配的代码(此时KMP数组为空)

PS: 代码中,i代表着在i个字符范围内,可以直接接续的位置,所以真正的其实点为1,但是当只有1个字符时,最优选就是它自己,所以直接跳过。另外,因为b数组的第一个下标为0,所以里边的i要写成i-1。

// 预处理KMP
int j=0;
for(int i=2;i<=lb;i++){
    while(j && b[i-1]!=b[j]){
        j=kmp[j];
    }
    if(b[i-1]==b[j]) j++;
    kmp[i]=j;
}
以下是完整代码
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
string a,b;
int kmp[1000002];
int main(){
    cin>>a>>b;
    int la=a.length(),lb=b.length();
    // 预处理KMP
    int j=0;
    for(int i=2;i<=lb;i++){
        while(j&&b[i-1]!=b[j]){
            j=kmp[j];
        }
        if(b[i-1]==b[j]) j++;
        kmp[i]=j;
    }
    //实践匹配
    j=0;
    for(int i=1;i<=la+1;i++){
        if(j==lb){
            j=kmp[j];
            cout<<i-lb<<endl;
        }
        // cout<<a[i-1]<<" "<<b[j]<<endl;
        while(j&&a[i-1]!=b[j]){
            j=kmp[j];
        }
        if(a[i-1]==b[j]) j++;
    }
    for(int i=1;i<=lb;i++){
        cout<<kmp[i]<<" ";
    }
    return 0;
}

KMP算法详解
https://www.insaua.com/2023/08/11/KMP算法详解/
作者
Eason3Blue
发布于
2023年8月11日
许可协议