KMP 板子+总结理解

板子:

希望不要有错啊

void build(char s[],int n)//构造nxt数组相当于把匹配串错开一位自己进行比较
{
     int k=0;nxt[0]=0;
     for(int i=1;i<n;i++)
     {
          while(k&&s[i]!=s[k])//注意是while循环,因为可能回退一次之后依旧不相等
               k=nxt[k-1];
          if(s[i]==s[k])
               k++;
          nxt[i]=k;
     }
}
bool kmp(char w[],char s[],int lw,int ls)
{
     build(s,ls);
     int j=0;
     for(int i=0;i<lw;i++)
     {
          while(j&&w[i]!=s[j])//不相等就回退
               j=nxt[j-1];
          if(w[i]==s[j])//相等就++
               j++;
          if(j==ls)
               return true;//匹配串已经匹配完了bingo
     }
     return false;
}

--------------------------------------------------------------我只是分割线啊----------------------------------------------------------------------------

传说中,KMP算法唯一不好理解的地方就是nxt数组的构造 ?

KMP的思想还是比较好理解的:(为了方便,下面统一用T表示文本串,S表示匹配串)

         对于两串字符S和T,我们要判断 T 中是否包含了 S,比如给出T:ABABCB,S:ABC。暴力的话就是一个一个比,遇到不同的就把T串开头往后移一位,S串从第一位重新开始,就这样一直到完全相同---找到或者T串结束---未找到。

         但是KMP的不同在于:利用前面比对可以获得的信息来减少后面的无用比对次数。比如上面那个例子,我们匹配到T的第三位,发现与S串不一样了,按照之前的想法,应该是T串的开始往后移一位,S串从头开始,也就是T从第二位开始与S串重新开始对比;但是KMP是怎么做的呐?可以发现,由于T串的第二位跟第一位是不一样的,而我们已经比对过S、T前两位是吻合的(从第三位开始不一样)那么我们如果把T串仅仅往后移一位,让S串的第一位(等于T串的第一位)和T串的第二位比较,显然是不可能会匹配的。这就产生了无用的比对。                          让我们来看更明显的例子:T:ABABEFABABG,S:ABABG,当我们比对到第5位的时候发现不同了,而对于S串来说,对于第5位之前的字符串前缀2位和后缀2位完全相同(当让S串中也一样了),这就意味着T中的那个后缀再与S比较时是不用比较的(已经相等),也就是说,前缀后缀相同的长度我们都可以不用比较,假设是len,我们就可以直接让S从第len+1位开始比较(假设字符串下标从1开始),更便于代码:假设现在比较到了第 j 位,我们直接让S回退到第(j-len)位开始比较。

下 面 就 是 最 最 重 要 的 nxt 数 组 啦

      显然,根据上面的想法,nxt [ i ] 就是第 i 位之前的字符串的前缀后缀相同的最大长度是多少(我们肯定是要最大限度地少做比较嘛)

令字符串下标从0开始

      还是结合代码吧(实在写不下去,不好表达,多写几个例子马上就明白了)其中,nxt[i]表示,从0到 i 位形成的字符串的前缀后缀相同的最大长度。

(嘤!本来以为能写的清楚点的,因为自己理解就花了蛮久时间,发现真心不大好写……日后说不定会再补)

呼呼

猜你喜欢

转载自blog.csdn.net/destiny1507/article/details/81586478