KMP笔记

发布时间 2023-08-21 15:29:47作者: 11jiang08

KMP算法,是一种能在 \(O(n+m)\) 的时间内求出模式串 \(A\)(长度为 \(m\))在文本串 \(B\)(长度为 \(n\)) 中出现的次数及位置的字符串匹配算法。

KMP算法共分为 \(2\) 步:

\(1\) 步,对 \(A\) 串进行自我匹配,求出 \(nxt\) 数组,\(nxt[i]=max\{j\}\),其中 \(j<i\)\(A[i-j+1 \sim j]=A[1 \sim j]\)

\(2\) 步,用 \(A\) 串去匹配 \(B\) 串,求出 \(f\) 数组,其中 \(f[i]=max\{j\}\),其中 \(j \leq i\) 并且 \(B[i-j+1 \sim i]=A[1 \sim j]\)

如何快速计算 \(nxt\) 数组?

\(j_0\)\(nxt[i]\) 满足条件的选项(以下称为“候选项”),那小于 \(j_0\) 中最大的候选项是 \(nxt[j_0]\)

在计算 \(nxt[i]\) 时,只要把 \(nxt[i-1]+1\)\(nxt[nxt[i-1]]+1\)\(...\) 作为候选项即可。

\(f\) 数组可以用相同方法计算。

#include<iostream>
#include<cstring>
#define MAXN 1000005
using namespace std;
int Next[MAXN];
int len_a,len_b; 
char a[MAXN],b[MAXN];
int main(){
    cin >> a+1;
    cin >> b+1;
    len_a = strlen(a+1);
    len_b = strlen(b+1);
    Next[1] = 0;
    for (int i = 2,j = 0; i <= len_b; i++){     
        while(j > 0 && b[i] != b[j+1]) j = Next[j];
        if(b[i] == b[j+1]) j++;    
        Next[i] = j;
    }
    for (int i = 1, j = 0; i <= len_a; i++){
        while(j > 0 && b[j+1] != a[i]) j = Next[j];
        if (b[j+1] == a[i]) j++;
        //输出匹配位置,然后继续匹配
        if (j == len_b) { cout << i-len_b + 1 << endl; j = Next[j];}
       }
    for (int i = 1; i <= len_b; i++)
    cout << Next[i] << " ";
    return 0;
}