很不详细的KMP

KMP

我都初三了还不会KMP……

全称The Knuth-Morris-Pratt Algorithm,三个大佬同时发明
只适用于单模匹配,可以求子串在母串中出现的位置次数等东西

普通匹配是失配了重新从母串下一位、子串第一位开始匹配,最坏时间复杂度 O(nm) O ( n m )
KMP K M P 思想核心是建立 next n e x t 数组,利用失配信息快速匹配,最坏时间复杂度 O(n) O ( n )

next

网上其他教程写next写的跟sh*t一样
我写简单一点,对于子串的每一位建 next n e x t

  • i i 位的 next n e x t 表示以 i i 为结尾的最长的、且从第一位字符开始存在的字符串的末尾位置

这个可以子串自己和自己匹配实现
如果当前建 next n e x t 到第 i i 位,看一下 next[i]+1 n e x t [ i ] + 1 位和 i+1 i + 1 相不相同
相同的话 next[i+1]=next[i]+1 n e x t [ i + 1 ] = n e x t [ i ] + 1 ,否则 i=next[i] i = n e x t [ i ] 重新回溯做
(大概像把 i+1 i + 1 next n e x t 再指向 next n e x t next n e x t ,有点像 AC A C 自动机)

所以next是往前跳的为什么叫做next

匹配

搞完 next n e x t ,匹配很简单
i,j i , j 分别是母串、子串匹配到了哪一位
如果 i,j i , j 位置不匹配就 j=next[j] j = n e x t [ j ] ,否则 i++,j++ i + + , j + +
j==len j == l e n 子 串 ,就匹配成功一次
多次匹配就继续做 KMP K M P 直到 i i 指针 ==len == l e n 母 串

code

  • 丢个模板
#include<stdio.h>
#include<string.h>
#define MAXN 100005

using namespace std;

char s1[MAXN],s2[MAXN];
int len1,len2,i,j,k;
int next[MAXN];

void init()
{
    k=-1,j=0;
    next[0]=-1;
    while (j<len2)
    {
        if (k==-1 || s2[k]==s2[j])
        {
            j++;
            k++;
            next[j]=k;
        }
        else k=next[k];
    }
}

void kmp()
{
    j=0;
    while (i<len1 && j<len2)
    {
        if (j==-1 || s1[i]==s2[j])i++,j++;
        else j=next[j];
    }
    if (j==len2)printf("%d\n",i-j+1);
}

int main()
{
    scanf("%d%d",&len1,&len2);
    scanf("%s%s",s1,s2);
    init();
    kmp();
    while (1)
    {
        if (i==len1) break;
        i=i-j+2;
        kmp();
    }
    return 0;
}
点赞