zoukankan      html  css  js  c++  java
  • KMP

    KMP算法之所以叫做KMP算法是因为这个算法是由三个人共同提出来的,就取三个人名字的首字母作为该算法的名字。其实KMP算法与BF算法的区别就在于KMP算法巧妙的消除了指针i的回溯问题,只需确定下次匹配j的位置即可,使得问题的复杂度由O(mn)下降到O(m+n)。

    在KMP算法中,为了确定在匹配不成功时,下次匹配时j的位置,引入了next[]数组,next[j]的值表示P[0...j-1]中最长后缀的长度等于相同字符序列的前缀。

    对于next[]数组的定义如下:

    1)next[j]=-1  j=0

    2)next[j]=max k:0<k<j P[0...k-1]=P[j-k,j-1]

    3)next[j]=0  其他

    如:

    P      a    b   a    b   a

    j       0   1    2   3   4

    next -1  0    0   1   2

    即next[j]=k>0时,表示P[0...k-1]=P[j-k,j-1]

    因此KMP算法的思想就是:在匹配过程称,若发生不匹配的情况,如果next[j]>=0,则目标串的指针i不变,将模式串的指针j移动到next[j]的位置继续进行匹配;若next[j]=-1,则将i右移1位,并将j置0,继续进行比较。

    代码实现如下:

    int KMPMatch(char *s,char *p)
    {
        int next[100];
        int i,j;
        i=0;
        j=0;
        getNext(p,next);
        while(i<strlen(s))
        {
            if(j==-1||s[i]==p[j])
            {
                i++;
                j++;
            }
            else
            {
                j=next[j];       //消除了指针i的回溯
            }
            if(j==strlen(p))
                return i-strlen(p);
        }
        return -1;
    }
    因此KMP算法的关键在于求算next[]数组的值,即求算模式串每个位置处的最长后缀与前缀相同的长度, 而求算next[]数组的值有两种思路,第一种思路是用递推的思想去求算,还有一种就是直接去求解。

      1.按照递推的思想:

       根据定义next[0]=-1,假设next[j]=k, 即P[0...k-1]==P[j-k,j-1]

       1)若P[j]==P[k],则有P[0..k]==P[j-k,j],很显然,next[j+1]=next[j]+1=k+1;

       2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。

       因此可以这样去实现:

    void getNext(char *p,int *next)
    {
        int j,k;
        next[0]=-1;
        j=0;
        k=-1;
        while(j<strlen(p)-1)
        {
            if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k]
            {
                j++;
                k++;
                next[j]=k;
            }
            else                   //p[j]!=p[k]
                k=next[k];
        }
    }

    但是这个不是最优的,因为他没有考虑aaaaaaaaaaaaaaaaaaab的情况,这样前面会出现大量的1。

    改进:

    void getNext(char *p,int *next)
    {
        int j,k;
        next[0]=-1;
        j=0;
        k=-1;
        while(j<strlen(p)-1)
        {
            if(k==-1||p[j]==p[k])    //匹配的情况下,p[j]==p[k]
            {
                j++;
                k++;
                                         //新加入的判断语句
                       if(p[j]!=p[k])
                         next[j]=k;
                   else
                        next[j]=next[k];
            }
            else                   //p[j]!=p[k]
                k=next[k];
        }
    }
  • 相关阅读:
    不务正业系列-浅谈《过气堡垒》,一个RTS玩家的视角
    [LeetCode] 54. Spiral Matrix
    [LeetCode] 40. Combination Sum II
    138. Copy List with Random Pointer
    310. Minimum Height Trees
    4. Median of Two Sorted Arrays
    153. Find Minimum in Rotated Sorted Array
    33. Search in Rotated Sorted Array
    35. Search Insert Position
    278. First Bad Version
  • 原文地址:https://www.cnblogs.com/richardcpp/p/2745979.html
Copyright © 2011-2022 走看看