很不详细的KMP

KMP

我都初三了还不会KMP……

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

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


next

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

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

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

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


匹配

搞完 n e x t ,匹配很简单
i , j 分别是母串、子串匹配到了哪一位
如果 i , j 位置不匹配就 j = n e x t [ j ] ,否则 i + + , j + +
j == l e n ,就匹配成功一次
多次匹配就继续做 K M P 直到 i 指针 == 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;
}

猜你喜欢

转载自blog.csdn.net/enjoy_pascal/article/details/81435631