kmp算法讲解及其模板

时间:2019-09-29
本文章向大家介绍kmp算法讲解及其模板,主要包括kmp算法讲解及其模板使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、前言

kmp算法是用于从文本串text的字串中,寻找含有的模板串pattern的数量/位置的算法。
例如,在文本串abcabcccabc中,模板串abc的数量有3个,其起始位置是0,3,8。

二、思路

暴力是两个for循环O(nm)搞定,显然不够优雅,而kmp则是O(n+m)。

kmp说实话,有点绕,但其实关键就一点:寻找模板串中最长的相同后缀与前缀,并通过next数组存储

如何理解?举个栗子

对于模板串abcab而言,我们从头开始构造next数组

字串 前缀 后缀 最长公共后缀 next数组
"a" [] [] next[0] = 0
"ab" [a] [b] next[1] = 0
"abc" [a,ab] [c,bc] next[2] = 0
"abca" [a,ab,abc] [a,ca,bca] a next[3] = 1
"abcab" [a,ab,abc,abca] [b,ab,cab,bcab] ab next[4] = 2
"abcabc" [a,ab,abc,abca,abcab] [c,bc,abc,cabc,bcabc] abc next[5] = 3

对于文本串abcabb来说,当匹配到5,即abcabb时,模板串匹配到abcabc,此时该位置字符不同

当使用暴力算法时,文本串必须跳回1位置,即b,而模板串必须跳回初始位置,重新匹配

当使用kmp算法时,模板串next[当前位置-1 = 4] = 2,即跳到2位置,此时模板串为abc,而文本串为abcabb,发现了吗?模板串前缀abc与文本串后缀abb拥有相同前缀ab,于是模板串就不需要回到原点了,可以继续对比,即此时文本串为abcab,而模板串为ab,然后对比接下来的字符。

三、代码

int nextt[maxn];
void get_nextt(char pattern[]){//为pattern字符串创建nextt数组
    nextt[0] = 0;
    int max_length = 0;
    for(int i = 1;pattern[i];i++){
        while(max_length > 0 && pattern[max_length] != pattern[i])
            max_length = nextt[max_length-1];
        if(pattern[i] == pattern[max_length])
            max_length++;
        nextt[i] = max_length;
    }
}
queue<int> search(char text[],char pattern[]){//从test字符串中,寻找含有多少个pattern字符串,并将其开头位置存入队列中
    queue<int> q;
    int pattern_length = strlen(pattern);
    get_nextt(pattern);
    int count = 0;
    for(int i = 0;text[i];i++){
        while(count > 0 && pattern[count] != text[i])
            count = nextt[count-1];
        if(pattern[count] == text[i])
            count++;
        if(count == pattern_length){
            q.push(i-pattern_length+1 );
            count = nextt[count-1];
        }
    }
    return q;
}

原文地址:https://www.cnblogs.com/MMMMMMMW/p/11607518.html