KMP算法

作者: KevinHwong | 来源:发表于2017-01-09 19:00 被阅读0次

    问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置
    输入:“abcdef”,“bc”
    "abcdefg" ,"ba"
    输出:1
    -1

    暴力匹配

    并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有:
    如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符;
    如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。

    int violent(char *s,char *p){
        int sLen = strlen(s);
        int pLen = strlen(p);
        int i = 0;
        int j = 0;
        while(i<sLen && j<pLen){
            if(s[i] == p[j]){
                i++;
                j++;
            }
            else{
                i = i-j+1;
                j = 0;
            }
        }
        //匹配成功,返回模式串p在文本串s中的位置,否则返回-1
        if (j == pLen)
            return i - j;
        else
            return -1;
    
    }
    

    KMP 算法
    下面先直接给出KMP的算法流程(具体教程:<a href= http://blog.csdn.net/v_july_v/article/details/7041827> 详细教程传送门</a>):
    假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置
    如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),都令i++,j++,继续匹配下一个字符;
    如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S向右移动了j - next [j] 位。
    换言之,当匹配失败时,模式串向右移动的位数为:失配字符所在位置 - 失配字符对应的next 值,即移动的实际位数为:j - next[j],且此值大于等于1。(实际上相当于当前位和next[j]位比)

    void GetNext(char* p,int next[])
    {
        int pLen = strlen(p);
        next[0] = -1;
        int k = -1;
        int j = 0;
        while (j < pLen - 1)
        {
            //p[k]表示前缀,p[j]表示后缀
            if (k == -1 || p[j] == p[k])
            {
                ++k;
                ++j;
                if (p[j] != p[k])
                    next[j] = k;   //之前只有这一行
                else
                    //因为不能出现p[j] = p[ next[j ]],所以当出现时需要继续递归,k = next[k] = next[next[k]]
                    next[j] = next[k];
            }
            else
            {
                k = next[k];
            }
        }
    }
    int kmp(char *s,char *p){
        int sLen = strlen(s);
        int pLen = strlen(p);
        int next[pLen];
        GetNext(p,next);
        int i = 0;
        int j = 0;
        
        while(i<sLen && j<pLen){
            if(j == -1 || s[i] == p[j]){
                i++;
                j++;
                
            }
            else{
                j = next[j];
            }
        }
        //匹配成功,返回模式串p在文本串s中的位置,否则返回-1
        if (j == pLen)
            return i - j;
        else
            return -1;
        
    }
    

    时间复杂度
    我们发现如果某个字符匹配成功,模式串首字符的位置保持不动,仅仅是i++、j++;如果匹配失配,i 不变(即 i 不回溯),模式串会跳过匹配过的next [j]个字符。整个算法最坏的情况是,当模式串首字符位于i - j的位置时才匹配成功,算法结束。 所以,如果文本串的长度为n,模式串的长度为m,那么匹配过程的时间复杂度为O(n),算上计算next的O(m)时间,KMP的整体时间复杂度为O(m + n)

    Reference:
    <a href="http://blog.csdn.net/v_july_v/article/details/7041827">从头到尾彻底理解KMP</a>

    相关文章

      网友评论

          本文标题:KMP算法

          本文链接:https://www.haomeiwen.com/subject/wbuhbttx.html