关于KMP算法的自我体会

关于KMP算法的自我体会

大家好,是我一名刚学编程没多久的萌新,你们可以叫我齐齐。在刚学学编程时候,觉得编程语言很繁杂且容错率几乎为零。为此我通过刷题打码,努力增加对代码的熟悉度,终于挺过来第一个学期。在第二个学期,遇到了计算机的一个难点——算法

算法是一种很神奇的东西,它能使时间复杂度从三次方,二次方降至一次方型。今天我就以我自己的理解分析KMP算法。

我们先来对常规算法BF算法进行回顾:
在这里插入图片描述

在不同的BF算法下,会通过对主串的每一个元素进行逐个匹配。比如在上图中,p代表主串中第几个元素进行匹配,q代表子串中第几个元素进行匹配。

while( p < i.length && q < j.length )
{
     if( i[p] == j[q] )
     {
         p++; q++;
     }
     else
     {
         p = p - q + 1;  //加1是为了让主串的匹配到下一个元素
         q = 0;
     }
}

效果如图:

在这里插入图片描述

当遇到D不与主串中的C匹配时,算法将p回溯到第二个元素(B),q回溯到初始元素(A),在进行第二轮的匹配。

原理分析

在刚刚的BF算法中,我们可以发现,在已经完成子串匹配的几个元素(ABA)其实是已知的,但是下一次当我们在进行匹配时,BF算法是直接忽略,直接从主串第二个开始匹配,而我们已知主串中第二个元素是B,根本不是子串中的首元素,所以其实不用比较!

以上的BF算法效率极低,当遇到较长的字符串就显得十分吃力。因此,dalao们想到了一种算法:KMP算法。

void Getnext(int next[],String t)
{
   int j = 0 , k = -1;  // j 指 t 中的元素,负责遍历,而 k 负责给 next[j]赋值
   next[0]=-1;  //定初始值
   while( j < t.length-1 )
   {
      if( k == -1 || t[j] == t[k] )
      {
         j++;k++;
         next[j] = k;
      }
      else k = next[k];  //溯源,究极难点!!!!!!!!!!
   }
}

算法创新以及难点:NEXT数组

第一种情况:当 k == -1 ,next[0] 值为 -1

执行 if 语句后 j++,k++ ,next【1】 = 0 。将 k初始值设为 -1 是为了后面的计算更加方便。

第二种情况:当 t[j] == t[k] 时候,举个例子

在这里插入图片描述

例如当 t【k】= t【j】时,则必有 t[0]…t[k-1]" = " t[j-k]…t[j-1](图中红蓝相匹配)此时的 k 为相同子串的长度,因为当next[j] = k 时候,可以理解为当主串的的都与子串的红色区域相同

如下图:

在这里插入图片描述

我们发现,主串中的蓝色部分与子串中的黄色部分相同,此时就不用重复比较子串前面的黄色格子了,直接将主串的B与子串的C比较。

第三种情况:t[j] != t[k]

当遇到这种情况,我用一张图来解释这个情况:

在这里插入图片描述

我们发现 t[0] ~ t[k-1] 与 t[j-k] ~ t[j-1] 是相同的,因而与子串头部相同的元素个数为 k ,当 j++,k++ 后发现,t[k] != t[j],也就是说,已经不存在与子串头部相同的最长元素组【ABA】,但是我们发现,会存在一种情况,即蓝色区域【BAB】中的可能还存在与子串头部相同的元素组合,比如图中蓝色区域的【AB】。

如果你还有点迷惑,可以通俗认为,既然之前最长的串【ABAB】已经不能与子串的头部【ABAC】相同,但是仍然有机会使得【ABAB】中存在与子串头部相同的元素串,即【ABAC】和【ABAB】中的【AB】。

那现在怎么让程序知道我们刚刚想的这一步呢???

答案就是溯源!我们刚刚已经求得最大的相同元素串长度为 k ,在上一张图中 k = 4,【ABA】,k = next[k] 这一步意义在于,在【ABA】的内部中看能否找到与蓝色部分相同的元素组。如果没有就继续循环,直到找到符合重合的子串或者 k == -1。

通俗来讲就是自己这个最大已经不能与子串头元素组匹配了,就从自己本身【ABA】中往自己内部寻找,k指针会一直在字串的头部扫来扫去,寻找着最大的 t[0] ~ t[k-1] 与 t[j-k] ~ t[j-1] , 如果找不到就以 k 点位置来溯源,通过 k = next[k] ,直到在内部中找到 t[k] = t[j] 或者 k已经指到第一个元素 A,说明已经在 t[j-k] ~ t[j-1] 中找不到任何一个元素组与子串的头元素组相同。

这里我们给出完整的KMP算法的程序

int KMP(String s,String t)
{
   int next[MaxSize],i=0;j=0;
   Getnext(t,next);
   while(i<s.length&&j<t.length)
   {
      if(j==-1 || s[i]==t[j])
      {
         i++;
         j++;
      }
      else j=next[j];               //j回退。。。
   }
   if(j>=t.length)
       return (i-t.length);         //匹配成功,返回子串的位置
   else
      return (-1);                  //没找到
}

如果你能看完的话,希望你也能明白KMP算法的精髓,编程世界奇妙且深奥,相同的问题会有更优质的算法,希望各位同学能努力学习,快乐学习!!!我是齐齐,再见!!!

本博客参考了:https://blog.csdn.net/dark_cy/article/details/88698736
以及:https://www.cnblogs.com/yjiyjige/p/3263858.html
有兴趣的同学也可以去看看!

猜你喜欢

转载自blog.csdn.net/MrChen666/article/details/106211949