KMP算法初入小结

初学kmp算法。看了好几个小时,做了几道题才有点懂。kmp核心在于next数组。看懂了有限状态自动机,看kmp就很容易懂了。

next数组:

模式P[1..m] 。 前k个P[1,,k]记为Pk,next[q]就是在Pq中找到最大的真后缀等于Pk (k < q,Pq的真后缀P的最长前缀长度),P[1…k]==P[q-k+1….q],next[q]就等于k。证明可以看算法导论。kmp算法详解

next数组周期性:

如果len%(len-next[len])==0,那么字符串以len-next[len]为最小循环节,循环len/(len-next[len])次。
证明:循环节证明
并且无论len%(len-next[len])==0是否成立,T=len-next[len]必然为最小循环节。
证明(自己的想法,不是很严谨):假设存在t是最小周期,那么T=kt必然成立(k为大于1整数),那么很显然next[len]还能更大,这不就矛盾了。画图可以很直观的体现出来,类似上面的循环节证明。

next数组求解:

假设我们知道了next[0]到next[i],现在来求解next[i+1]。假设next[i]=k,就是说当前这个长为i的子串的前缀Pk等于Pi的后k个,P[1,k]==P[i-k+1,i],如果P[k+1]==P[i+1],因此P[1,K+1]==P[i-k+1,i]那么next[i+1]=next[i]+1。如果上面等式不成立,k=next[k]继续向下匹配,直到等式成立。关键在于next[0]=-1,这个用来处理如果都失配。该处的next则得到0。

kmp代码:

#include<iostream>
using namespace std;
const int maxn=10000005;
int kmp_next[maxn];
void getNext(string p)
{
    int siz=p.size();
    int i=0,j=-1;
    kmp_next[0]=-1;
    while(i<siz)
    {

        if(j==-1||p[i]==p[j])
        {
            kmp_next[++i]=++j;
        }
        else j=kmp_next[j];
    }
}
int KMP(string T,string p)
{
    getNext(p);
    int T_siz=T.size();
    int i,j=0;
    int m=p.size();
    int ans=0;
    for(i=0;i<T_siz;++i)
    {
        while(j!=-1&&T[i]!=p[j])j=kmp_next[j];
        j++;

        if(j>=m)
        {
            //匹配到了
             j=kmp_next[j];
             ans++;
             cout<<i<<endl;
        }
    }
    return ans;
}
int main()
{

    return 0;
}

有什么错误请指出。

猜你喜欢

转载自blog.csdn.net/PinappleMi/article/details/80767557
今日推荐