关于KMP算法中next数组的一些见解

引言

本篇主旨不是讲解KMP算法,而是为了讲解KMP算法中关于求解next数组的一些疑惑,相信很多人都会有,如果你没有,那您真的真的是很厉害(膜拜),也有可能你只是知道代码怎么写,并不知道其中的奥妙,接下来我就分享一下这个折磨我好久的奥妙。

先上代码

这是李春葆数据结构教程上的代码,网上广为流传的也都大同小异但是唯有一点不变的是else k = next[k],这便是该算法的奥妙之处

void GetNext(SqString t,int next[])
{
   int j=0,k=-1;
   next[0]=-1;
   while(j<t.length-1)
   {
      if(k == -1 || t.data[j] == t.data[k])
      {
         j++;k++;
         next[j] = k;
      }
      else k = next[k];//k回退,为什么是回退到next[k],这就是接下来我们要探讨的问题
   }
}

这几天我也有看过很多人的帖子,但是秉持着一种吃现成想法的我,当看到一大堆的文字和字母时,选择了放弃,但是程序员怎么可能轻言放弃,最后我是在《算法笔记》这本书上找到了灵感,如果你有的话可以去看一下,或者你想去看那些大神写的帖子也可以去百度,百度前几个都是。

好了闲话不多说,接下来步入正题

如果你已经学习过了KMP算法,那么你应该知道next数组的含义,其实他有好几个含义,但是本质上都是一样的,但是现在我还需要你记住其中一种含义,那就是
next[j]指的是模式串T中第Tj(下标从零开始)个字符前最长有多少个字符(后缀)与T开头的字符(前缀)相同
有了这个,接下来我们来模拟求解next数组的过程

下图是在一次匹配过程中匹配失败后的场景,图中蓝色部分是匹配成功的部分,这就说明蓝色部分的字符串是完全相同的
在这里插入图片描述
匹配失败说明此时在箭头J之前我们找不到比蓝色部分更长的相等前后缀了,那么我们就退而求其次找找看有没有稍微短一点的相等前后缀,那么问题来了,我们从何找起呢,我们要充分利用一切可利用的资源,当我们求到next[j]时,那么next[k]肯定已经求出来了,那么我们看看next[k]提供给了我们什么信息
在这里插入图片描述
next[k]的值就是上图中箭头K前面的字符串的最长相等前后缀的长度。假设最长相等前后缀就是图中A和B箭头所指的位置,那么A和B指向的字符串完全相同,别忘了之前的结论,蓝色部分也是完全相同,所以我们可以得出A,B,C,D四个箭头指向的字符串都是相同的.

既然箭头A,D所指向的字符串是相同的,那么我们就找到了稍微短一点的相等前后缀;如下图所示,这时我们只需要将箭头J和K’(不是K)所指向的字符进行比较(既代码中的第7行),那么这个K’的位置其实就是next[k]的值(千呼万唤始出来),既代码中的k = next[k],接下来就是按照程序一步一步走下去了。
在这里插入图片描述
至此,next数组也就结束了,虽然我也是写的长篇大论,但是我没有用具体的字符串举例子,所以省去了很多令人头皮发麻的字母,也算是有所改进吧。

希望可以帮到有此疑惑的你,如果有想看复杂版的,这是他的博客

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值