字符串匹配KMP算法

假设我们的字符串母串是T,子串是W,我们想找到子串在母串中出现的位置并统计总的出现次数,可以使用KMP算法。KMP算法需要先求解失配函数next(i),失配函数的意义如下:T_{[0, i-1]}的最长公共前后缀是T_{[0, next(i)-1]}T_{[0, N]}的最长公共前后缀是T_{[0, k]}的含义是k是最大的满足k<NT_{[0, k]}=T_{[N-k, N]}的非负整数)。

求失配函数需要用到全局变量:

const int MAXW = 10000+5;
char W[MAXW]; // 子串
int nex[MAXW]; // 失配函数,即next(i)=nex[i]

求失配函数的代码如下:

nex[0] = -1; // 特殊规定nex[0]的值为-1
int i, j;
for(i=0;W[i];i++){
    // 根据nex[i]的值求nex[i+1]的值
    // nex[i]=0表示不存在最长公共前后缀
    j = nex[i];
    while(j>=0 && W[j]!=W[i]) j = nex[j];
    nex[i+1] = j+1;
}

但实际上失配函数还有可以优化的地方,对于T_{[0, i-1]}的最长公共前后缀T_{[0, next(i)-1]},假如T_i=T_{next(i)},则在T_i处失配时必定也将继续在T_{next(i)}处失配,故可以改进失配函数。改进失配函数next(i)的含义如下:T_{[0, next(i)-1]}T_{[0, i-1]}的最长的满足T_i\ne T_{next(i)}的公共前后缀。

求改进失配函数的代码如下:

nex[0] = -1; // 特殊规定nex[0]的值为-1
int i, j;
for(i=0,j=-1;W[i];i++){
    // 根据nex[i]的值求nex[i+1]的值
    // nex[i]=0表示不存在最长公共前后缀
    // 此时j等于未改进时的失配函数nex[i]
    while(j>=0 && W[j]!=W[i]) j = nex[j];
    nex[i+1] = W[i+1]==W[++j] ? nex[j] : j;
}

求好了失配函数之后,便可以利用失配函数进行字符串匹配了。需要用到的全局变量:

const int MAXT = 1000000+5;
const int MAXW = 10000+5;
char T[MAXT], W[MAXW]; // T是母串,W是子串
int nex[MAXW]; // 之前求出的失配函数

KMP算法利用失配数组进行字符串匹配的具体代码如下:

int i, j, ans = 0; // ans表示W在T中出现的次数
for(i=j=0;T[i];i++){
    // 此时已经匹配到了W[j-1]和T[i-1]
    while(j>=0 && W[j]!=T[i]) j = nex[j];
    if(!W[++j]) ans++;
}

附上一道KMP模板题:POJ3461 Oulipo

AC代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXW = 10000+5;
const int MAXT = 1000000+5;
int nex[MAXW];
char W[MAXW], T[MAXT];
int main(){
    int TC; scanf("%d", &TC);
    while(TC--){
        scanf("%s%s", W, T);
        memset(nex, 0, sizeof(nex));
        nex[0] = -1;
        int i, j, ans = 0;
        for(i=0,j=-1;W[i];i++){
            while(j>=0 && W[j]!=W[i]) j = nex[j];
            nex[i+1] = W[i+1]==W[++j] ? nex[j] : j;
        }
        for(i=j=0;T[i];i++){
            while(j>=0 && W[j]!=T[i]) j = nex[j];
            if(!W[++j]) ans++;
        }
        printf("%d\n", ans);
    }
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 字符串匹配: KMP算法 学习于 从头到尾彻底理解KMP 结合自己的理解, 本文致力于从简介绍 先给出模板代码v...
    Shadow0x70阅读 441评论 0 0
  • KMP算法目的:尽快解决字符串匹配问题,时间复杂度为O(m+n),而常规的简单匹配算法时间复杂度:O(m*n) 这...
    安静1337阅读 984评论 0 51
  • 字符串匹配KMP算法详解 1. 引言 以前看过很多次KMP算法,一直觉得很有用,但都没有搞明白,一方面是网上很少有...
    张晨辉Allen阅读 2,430评论 0 3
  • 字符串匹配(查找)算法是一类重要的字符串算法(String Algorithm)。有两个字符串, 长度为m的hay...
    曾会玩阅读 617评论 0 2
  • 文|君若清晖 我羞涩着从他身边走过,假装不去看他。他酷酷的投篮动作,一直是我眼角最独特的风景。我好想对他说,我喜欢...
    君若清晖阅读 307评论 2 5