KMP算法入门 KMP算法


理解

KMP算法的核心,是一个被称为部分匹配表(Partial Match Table)的数组。我觉得理解KMP的最大障碍就是很多人在看了很多关于KMP的文章之后,仍然搞不懂PMT中的值代表了什么意思。这里我们抛开所有的枝枝蔓蔓,先来解释一下这个数据到底是什么。

对于字符串“abababca”,它的PMT如下表所示:

KMP算法入门
KMP算法

PMT中的值是字符串的前缀集合与后缀集合的交集中最长元素的长度

我们看到如果是在 j 位 失配,那么影响 j 指针回溯的位置的其实是第 j −1 位的 PMT 值,所以为了编程的方便, 我们不直接使用PMT数组,而是将PMT数组向后偏移一位。我们把新得到的这个数组称为next数组。

KMP算法入门
KMP算法

例题

HDU1711

给定两个数组,问能不能再第一个数组中匹配得到第二个数组,如果可以,那么输出最早匹配的起始位置,否则输出-1

代码:

#include<bits/stdc++.h>
using namespace std;

int s[1000005],p[10005], ne[10005];//next是关键字
int n, m;

void getNext(){
    int i = 0, j = -1;
    ne[0] = -1;
    while(i < m){
        if(j == -1 || p[i] == p[j]){
            i++; j++; ne[i] = j; //attention!
        }
        else j = ne[j];
    }
}
int KMP(){
    int i = 0, j = 0;
    getNext();
    while(i < n &&j <m){
        if(j == -1 || s[i] == p[j]){
            i++; j++;
        }
        else j = ne[j];
    }
    if(j == m) return i - j + 1;
    return -1;
}
int main(){   
    int t;
    cin >> t;
    while(t--){
        cin >> n >> m;
        for(int i = 0; i <n; i++) scanf("%d",&s[i]);
        for(int i = 0; i < m ;i++) scanf("%d",&p[i]);
        int t = KMP();
        cout << t << endl;
    }
    system("pause");
}