关于Kmp

Posted scalecx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Kmp相关的知识,希望对你有一定的参考价值。

Kmp就是在一个模板字符串p中找到和字串t相同的串的位置。

重点在于prefix数组的建立。prefix数组代表了t串每个位置截取当前长度的字串的最大相同前后缀。如:a为0, aa为1, ab为0, aabaa为2, aaaaa为4等等。

由于prefix数组代表最大相同前后缀,那么当我们把字串和模板串对比的时候,如果遇上两个不相等的字符,由于前面都匹配上了,所以我们只要把当前位代表的最大的相同前后缀长度的那一位移动到这里就行了,这样前面的已经匹配上的就不用再匹配一次。

 技术分享图片

 

可以看到上图第5位不同,那么由于第四位最大相同前后缀为1,那么前一位一定相同我们不用再比较,直接移动到第2位

 

 技术分享图片

这样反复进行最后就能找到结果。

(注意写代码时由于字符串由0位置开始,所以为了方便会将整个prefix数组向后移动一位,所以以下说的并不是最后实际的位置)

那么显而易见prefix[0]必然为0,我们用两个指针(此处不是C语言的那个指针),j指向第一位也就是t[0],i指向第二位也就是t[1]。如果i位置的字符等于j位置,那么prefix[i] = j,i和j都向后移动一位继续不相等的时候我们就往前去找这个位置对应的最大相同前后缀的那一位。(原理和Kmp搜寻时的一样,可以少做一些对比)

 

那么上代码:

首先是prefix数组的建立:

void Get_prefix()
{
    prefix[0] = -1;
    int i = 1, j = 0;
    while(i < m){
        if(t[i] == t[j]){
            j++;
            prefix[i+1] = j;//为了方便把整个prefix数组往后移一位,所以是i+1
            i++;
        }
        else{
            if(j > 0){
                j = prefix[j-1];
            }
            else{
                prefix[i+1] = 0;
                i++;
            }
        }
    }
}

然后是KMP主体代码:

void Kmp()
{
    int i = 0, j = 0;
    while(i < n){
        if(j == m - 1 && p[i] == t[j]){
            printf("%d
", i-j+1);
            j = prefix[j];//继续搜寻,如果只要第一个直接return就行
        }
        if(p[i] == t[j]){
            i++; j++;
        }
        else{
            j = prefix[j];
            if(j == -1){ 
                i++; j++;
            }
        }
    }
}

 

以上是关于关于Kmp的主要内容,如果未能解决你的问题,请参考以下文章

KMP算法

关于代码片段的时间复杂度

关于KMP算法

关于字符串问题KMP

关于片段生命周期

关于Kmp