学习笔记——KMP模式匹配

KMP模式匹配

KMP 算法能够在线性时间内判定字符串 \(A\left[1\sim N\right]\) 是否是字符串 \(B\left[ 1 \sim M\right]\) 的字串,并求出字符串 \(A\) 在字符串 \(B\) 中各次出现的位置。
详细来讲,KMP 算法分为两步。

  1. 对字符串 \(A\) 进行自我匹配求出一个数组 \(next\)\(next\left[i\right]\) 表示 \(A\) 中以 \(i\) 结尾的非前缀字串与 \(A\) 的前缀能匹配的最大长度。特别地当不存在这样的 \(j\) 时,\(next\left[i\right]\)\(0\),即:
    \(next\left[i\right] = \max\{j\}\),其中 \(j < i\)\(A\left[i-j+1 \sim i\right] = A\left[1\sim j\right]\)
  2. 对字符串 \(A\)\(B\) 进行匹配求出一个数组 \(f\),其中 \(f\left[i\right]\) 表示 \(B\) 中以 \(i\) 结尾的字串与 \(A\) 的前缀能匹配的最大长度,即:
    \(f\left[i\right] = \max\{j\}\),其中 \(j\le i\)\(B\left[i-j+1\sim i\right] = A\left[1\sim j\right]\)
    整个算法时间复杂度为 \(\mathcal{O}(N + M)\)

\(next\) 数组的求法

  1. 初始化 \(next\left[1\right] = j = 0\),假设 \(next\left[1\sim i-1\right]\) 已求出,求解 \(next\left[i\right]\)
  2. 不断尝试扩展匹配长度 \(j\),如果扩展失败即下一个字符不相等,则令 \(j=next\left[j\right]\),直至 \(j=0\),应该重新从头开始匹配。
  3. 如果扩展成功,匹配长度 \(j\) 就加一,\(next\left[i\right]\) 的值就是 \(j\)
nxt[1]=0;
for(int i=2,j=0;i<=n;i++){
    while(j&&a[i]!=a[j+1])j=nxt[j];
    if(a[i]==a[j+1])j++;
    nxt[i]=j;
}

\(f\) 数组的求法

与求解 \(next\) 数组基本一致。

for(int i=1,j=0;i<=m;i++){
    while(j&&(j==n||b[i]!=a[j+1]))j=nxt[j];
    if(b[i]==a[j+1])j++;
    f[i]=j;
}

Example

这里以Luogu P3375为例。
KMP 模版题,只需要输出 \(B\)\(A\) 中出现的位置,即当匹配长度 \(j\) 等于 \(B\) 字符串的长度时,\(B\)\(A\) 中出现,起点为 \(i-j+1\)

#include<bits/stdc++.h>
#define int long long
#define MAX 1000005
using namespace std;
string a,b;
int len1,len2,nxt[MAX];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin>>a>>b;
    len1=a.length();
    len2=b.length();
    a=" "+a,b=" "+b;
    for(int i=2,j=0;i<=len2;i++){
        while(j&&b[i]!=b[j+1])j=nxt[j];
        if(b[i]==b[j+1])j++;
        nxt[i]=j;
    }
    for(int i=1,j=0;i<=len1;i++){
        while(j&&a[i]!=b[j+1])j=nxt[j];
        if(a[i]==b[j+1])j++;
        if(j==len2){
            cout<<i-j+1<<'\n';
            j=nxt[j];
        }
    }
    for(int i=1;i<=len2;i++){
        cout<<nxt[i]<<' ';
    }
    return 0;
}
posted @ 2024-01-20 16:53  GyrthCurunír  阅读(10)  评论(0编辑  收藏  举报