KMP算法(一)

KMP看了不少,其实自己在暴力来算字符串匹配时,自己就想到了KMP算法的一个基本框架。
还是先来介绍一下KMP吧。
以下内容来自百度百科

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。

简单来讲,就是在暴力算法一次只移动一位,而KMP一次可以移动好几位,比方说我们要用abcabnfk来匹配一个长串。然后我们发现子串的第五个字符失配了,那么我们就可以把这个长串的当前位和它的第二位对齐,(看了不少KMP资料的你可能会问为什么不直接返回到0因为和b失配就必然和之前的b失配,那么直接回0不是更好,这个问题我等下再说。)也就是后移整个子串3位,肯定的结果是,再次失配,然后向前移动2个字符,返回0这个位置。但是你会发现这个比暴力的方法要快上不少,但显然这个算法并没有做到极致,而极致上的算法应该是直接返回到0这个位置,但KMP算法并没有到达极致(我也忘了到没到了),不过一个跳转表的概念还是给后人留下了非常深刻的印象的。
跳转表是啥?
我们定义一个next数组为:
next[i] = {从1~i的字符串中,使得前缀和后缀长度相同的最大的长度值};
也就是说,我们的字符串为s,那么某一个next一定是这样来计算的:

int find_next(){
int k;
for(k = 1;k <= i ; k ++)
    for(int j = 1;j <= k ; j ++)
        if(s[j] != s[i - j])break掉两重循环。
return k;

匹配到第i个失配时,通过平移i - next[i]使之与母串对齐,这就是next的数组应用之一。
这种求法显然很低效,我们必须想一想比较厉害的求法。
我们会发现其实我们在求n的next时,已经求出n-1的next了,考虑n-1的next:
第一种情况:n-1的next=0,则if(s[n]==s[1])next[n]=1;
第二种情况:n-1的next!=0,则
if(s[n]==s[next[n-1]+1]){next[n]=next[n-1]+1;return;}
else {int j = next[n-1];while(j&&s[j + 1] != s[n] )j = next[j];}
if (s[ j + 1] == s[n])j++;
next[n]=j;
递推可以得到所有的next,为了便于理解我分成了两种情况但是实际上第一种情况和第二种情况,且包括它们的语句,其实质都是相同的,所以我们直接给出模版。

void calc () {//s表示子串
    int j = 0,len = strlen (s + 1);
    nxt[1]=0;
    for (int i = 2; i <= len; ++ i) {
        while (j && s[j + 1] != s[i]) j = nxt[j];
        if (s[j + 1] == s[i]) ++ j;
        if (s[j] != s[nxt[j]])nxt[i] = j;
        else nxt[i]=nxt[j];
    }
    for(int i =1; i <= len ; ++ i)
        printf("%d ",nxt[i]);
}
void match(){//不可重叠的字符匹配,如果可重叠,那么只需要j=nxt[j];
    int j = 0,ans = 0,len = strlen (str + 1),lenc = strlen (s + 1);
    for(int i = 1;i <= len ;i ++){
        while (j && s[j + 1] != str[i])j = nxt[j];
        if(s[j + 1] == str[i])++ j;
        if(j == lenc){ans ++;j = 0;}
    }
    printf("%d\n",ans);
}

那么我们为什么要用KMP的低效算法的模版呢?原因有下:
1.next数组有其他的应用。
2.高效的算法有点长懒的写。
3.O(n)的算法不能优化太多。
讲下其他的应用。
我们可以发现,有些位置的next可能相同,比如都是0……,将next[i]与i连接,我们会得到一棵树。
这棵树的性质有不少,比方说某一个点i的size(子树大小)是该前缀在整个字符串中出现的次数,还比如说,动物园。
NOI2014的,动物园。但是动物园此题我在此先不做讲解,就是因为某种原因(别掩饰,不就是没有过吗)。
咳,所以KMP算法(一)到此结束。

你可能感兴趣的:(算法,KMP)