傻逼kmp

最近在打字符串,自然也就打到了kmp

kmp算法是由D.E. Knuth、J.H.Morris和V.R. Pratt提出的虽然两位都不认识orz

kmp算法是用来比较字符串是否相同,也就是给定两个字符串,A串和B串,需要回答B串是否为A串字串,我们一般把等待匹配的字符串称之为主串,来匹配的字符串称为模式串

按照朴素算法来解肯定是很简单的,在A串中不断枚举一个开始节点,若是不匹配就世界退出并更换开始节点,设A,B串长度分别为m,n,这里没有给出代码就是懒

虽然有最好情况,在开始的时候就能匹配到,时间复杂度为O(n),但也会存在排除最后才能找到的情况,这时算法时间复杂度会退化为O(mn),这就有点难以接受了。。。

然而kmp算法就比较神奇,可以在O(n)的时间内跑完整个代码,非常稳定

那么这个算法到底怎么实现呢我也不知道简单来说,就是在A串枚举一个i,B串枚举一个j,看A[i]和B[j]是否匹配,如果匹配,则i和j都往后移一位,如果不匹配,则说明A串从1到i的字串和B串从1到j的字串并不匹配,我们需要在A串的1~i中枚举一个k,使A串的头k个字符和末尾k个字符匹配,使k越大越好(匹配的尽量长),再去跟B串匹配

其实kmp也可以算是朴素算法的进化版啦

模拟一遍

A a b a b a b a c a b a c a b a b a b

B a b a b a b

匹配到5时,我们发现了差异,A[5]=a,但是B[5]=b啊!

朴素算法的思考方式是

欸欸欸?不匹配?那行我从A串的第2个开始枚举起,那么我再来跑一遍

kmp的思维方式是

不匹配?观察A[1]~A[5],我们可以发现字串A[1]~A[3]和A[3]~A[5]是可以匹配的,那么我们将j换为4,i继续推进到6

知道找到最后我们才能找到答案

值得一提的是,如果是在不知道怎么读入字符串的同学,可以用cin和char(本蒟蒻就用的cin和charQAQ

挂个板子题

https://www.luogu.org/problem/P3375

emmm贴代码

#include<bits/stdc++.h>
using namespace std;
int nxt[1000010],A,B,j;
char a[1000010],b[1000010];
int main(){
    cin>>(a+1)>>(b+1);
    A=strlen(a+1);B=strlen(b+1);
    for (int i=2;i<=B;i++){     
           while(j&&b[i]!=b[j+1])j=nxt[j];    
           if(b[j+1]==b[i])j++;    
        nxt[i]=j;
    }
    j=0;
    for(int i=1;i<=A;i++){
        while (j>0&&b[j+1]!=a[i]) j=nxt[j];
        if (b[j+1]==a[i]) j++;
        if (j==B) {printf("%d\n",i-B+1);j=nxt[j];}
       }

    for (int i=1;i<=B;i++)
        printf("%d ",nxt[i]);
    return 0;
}

 

posted @ 2019-07-31 16:27  Xxyh  阅读(176)  评论(0编辑  收藏  举报