/* 返回顶部 */

Luogu P3375 【模板】KMP字符串匹配

第一次写kmp是2月,写错但AC了...第二次是6月,才发现...

现在是8月,第三次 /cy


传送门

KMP (D.E.Knuth - J.H.Morris - V.R.Pratt) 也叫看…,是一种改进的字符串匹配算法,核心是在匹配失败后减少已经匹配过的部分重新匹配。

 

原理

KMP是通过一个f[](fail)——或者叫next的“失配函数”来实现的。

把已经给出的串称为文本串,要在文本串中找的串称为模式串。

首先,求出模式串的失配函数。

fail函数的含义是:在到这一位为止,前缀=后缀的最长长度是多少。

这里的=是指完全相同,比如ABCABC这样的,而不是对称,并且可以有重叠。

特别地,前两位(f[0],f[1])为零。

比如串$ABABAC$,它的fail应该为$001230$ (ABA和ABA重叠了也没事)。

假设已经求好了fail,那么,假设有文本串$ABABABAC$。

$ABABABAC$

$ABABAC$ ←到这里,发现配不上了

 

$ABABABAC$

  $ABABAC$ ←退回到第三位,再试试

 

实现

求失配函数

求失配函数是一个自己和自己匹配的过程。

void getf() {
    f[0] = f[1] = 0;
    for(int i = 1; i < len2; i++) {
        int j = f[i];
        while(j && p[i]!=p[j]) j = f[j];
        if(p[i] == p[j]) f[i+1] = j+1;
        else f[i+1] = 0;
    }
}

已知第i位的失配函数f[i],要求第i+1位的。

设j=f[i]。f[i]一定在i前面,f[i]已经求好了。

如果字符串的i+1和j+1位不同(p[i]≠p[j]),那么j不断地跳到自己的失配函数f[j],直到匹配上或j=0为止。

如果匹配上,f[i+1] = j+1;

否则如果还是p[i]≠p[j],说明是j=0而不是匹配上了,那么f[j] = 0。

 

匹配

void kmp() {
    int j = 0;
    for(int i = 0; i < len1; i++) {
        while(j && s[i]!=p[j])j = f[j];
        if(s[i] == p[j])j++;
        if(j == len2) {
            printf("%d\n",1+i-len2+1);
            j = f[j];
        }
    }
}

文本串指针i,模式串指针j。

和刚刚类似,如果没匹配上,就不断把j跳到f[j]。

如果匹配上了,j往后一位,即j++。

 

完整代码如下

 

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#define MogeKo qwq
using namespace std;
#include<string>
const int maxn = 1e6+10;
int len1,len2,f[maxn];
string s,p;

void getf() {
    f[0] = f[1] = 0;
    for(int i = 1; i < len2; i++) {
        int j = f[i];
        while(j && p[i]!=p[j]) j = f[j];
        if(p[i] == p[j]) f[i+1] = j+1;
        else f[i+1] = 0;
    }
}

void kmp() {
    int j = 0;
    for(int i = 0; i < len1; i++) {
        while(j && s[i]!=p[j])j = f[j];
        if(s[i] == p[j])j++;
        if(j == len2) {
            printf("%d\n",1+i-len2+1);
            j = f[j];
        }
    }
}

int main() {
    cin>>s>>p;
    len1 = s.length();
    len2 = p.length();
    getf();
    kmp();
    for(int i = 1; i <= len2; i++)
        printf("%d ",f[i]);
    return 0;
}

 

posted @ 2019-08-08 08:57  Mogeko  阅读(136)  评论(0编辑  收藏  举报