KMP算法(二)(前缀表与具体实现)

KMP算法(一)(与暴力算法对比及主要思想)
书接上文
在(一)中我们讲到了,KMP算法与暴力算法对比的优点就在于特殊前缀表(这节我们称为next数组)的存在使得我们在匹配失败时,不需要再一个一个从头开始,而是根据特殊前缀表直接匹配对应位置,节省时间。
这节我们主要来讲解前缀表构建的思路及如何代码实现。
以下讲解较为细致,大佬找知识点可按目录选看,如果是没有基础小白建议一步步看,理解会更透彻。

前缀表与next数组

对于讲解前缀表,大多数教材会选择直接介绍next数组,next数组可以算的上是一个经过一步特殊操作的前缀表,两种的创建以下都会提到

构建思路

前缀表的定义在(一)中有,不在赘述。
本节不在写表头,以前缀值代表前后缀公共元素个数的最大值
前缀表作为一个表,在代码表示时,我们很容易想到用一个数组来表示,所以以下讲解时,会有一行多余的数据代表数组索引。
下面我们看一个简单的前缀表

字符串用例:ABABD
在这里插入图片描述
前缀表
在这里插入图片描述

前缀值的获取(前几位直观获取,举例讲解)

对于任意一个字符串,我们很容易得到它的第一个前缀字符(数组索引为0)对应的前缀值一定为0(因为第一个前缀字符只有一个字符A没有前后缀,所以也不存在公共元素)
在这里插入图片描述

在这里插入图片描述
而对于第二位(数组索引为1),我们理所应当的将其与第一位进行比较,如果第二位与第一位相同,则第二位对应的前缀值为1,否则前缀值为0。(第二位字符所组成的前缀字符串AB,它的前缀即为第一位字符,后缀即为第二位字符,若相同,则前后缀有一个公共元素,否则没有为零)
在这里插入图片描述
在这里插入图片描述

到了第三位(数组索引为2),这里我们就不能这么直观的观察出前缀值了。
观察前缀表
第三位与前面组成了一个三位字符串ABA对应数组索引为012。因为字符串长度为3,所以字符串前后缀最大长度只能为2,这里我们就会思考,最大长度的前缀与最大长度的后缀是否相同,从而得出公共长度的最大值呢。这里其实不需要我们思考,上一步前缀值已经告诉了我们答案。
在这里插入图片描述
上一步中我们得到第二位的前缀值为零,那么它能给我们的信息是否只有它的前缀后缀公共元素最大值为0呢,肯定是不止这些的。在第三步中,我们曾尝试判断最大前缀与最大后缀是否匹配,但我们却忽略了它们的组成。第三位相较于第二位字符多了一位,导致了最大前后缀的长度都增加了。但是它的最大前后缀的起点并没有变,当我们比较最大前后缀时,比较的第一个字符同第二步一样(即第三位中最大长度前缀AB与最大长度后缀BA在比较时依旧要先比较AB中的A和BA中B是否相同),所以这就使得了这一步比较我们可以直接从第二步得到答案,第二位B前缀值为0,即A与B未匹配,所以我们可以直接判断第三位中最大长度前缀AB与最大长度后缀BA不匹配,所以第三位所对应的前缀值小于2。此时我们从第二步得到结论后,仅需要在让次之长度(1)的前后缀做对比就行了,所以首位A与末位A匹配成功,得到前后缀公共元素的最大值为1,即第三位的前缀值为1
在这里插入图片描述
在这里插入图片描述
在第三位的分析之上我们再来讨论第四位(数组索引为3),很明显最大长度的前后缀依旧同第三位一样,同第三位分析过程,我们可以快速得到,三位长度的前后缀不是公共元素,接下来是两位长度的前后缀,这里我们再一次运用第三位的思想,在第三位中,由于我们通过第二位的前缀值很快做出判断得到第三位的前缀值,同理,在第四位中我们来分析第三位的前缀值又表示了些什么。
经过判断我们得到第三位的最大长度前后缀公共元素为1,换句话说由于长度为1,所以我们可以说第三位与第一位匹配成功,当我们找寻第四位前后缀公共元素时,我们由已知结论排除了原有的最大长度3,当我们试图匹配长度为2的前后缀时,我们发现判断起点再一次回到了第三位的判断,而第三位判断时,给出了我们第三位与第一位匹配成功的结论,所以我们可以直接继续进行长度为2的前后缀公共元素的讨论,即:第四位作为第三位的后一位有机会不与第一位比较,而是与排在第一位后一位的第二位做比较。所以第四位与第二位比较得到结果称为判断前缀值的关键,如果相等则我门应该得到前缀值为2(对于此例确实如此),如果不相等我们在另寻它法先不做讨论。这样看求第四位的前缀值关键是我们由第三位的前缀值1得到了第三位与第一位相同,可直接比较第四位与第二位。

前缀值的获取(总结结论,结论推导获取)

到了这里,我们应该对前缀值有一个更深层次的认识,前缀值不仅仅代表着对应位置字符串前后缀公共元素长度的最大值,因为是前后缀的公共元素,它还可以表示该位置与从字符串首位起固定位置的字符相同,即指向自身与其相同的元素的位置。但是如上所说,相同的字符并不一定会有前缀值指引,需强调“前后缀的公共元素”,即未参与过“前后缀的公共元素”的字符的前缀值自然不会有所指向。
在这里插入图片描述
在这里插入图片描述

这里我们给出一个较长的字符串的前缀表,让大家直观的感受下
在这里插入图片描述
对于上述所说未参与过“前后缀的公共元素”的字符,我们也给出举例
在这里插入图片描述
所以,根据以上例子我们可以得到一个结论:
对于某一位置的前缀值,我们可以将该位置元素与前一位的前缀值对应位置的下一位(前一位元素p的前缀值对应位置的元素q与其相同,即p=q)进行匹配,以此来判断前缀值或者前后最大长度继续增加还是就此中断。

到这里,应该会有读者发现这个数组索引笔者贯穿始终,甚至影响理解与观感笔者都未将其删除,这是因为因为在代码实现中,我们的真值表就是以数组的形式所形成,口头解释可以便于我们理解,但理解的同时我们也要适应机器语言,不仅如此数组索引在这里还有着神奇的作用帮助我们简化了结论,由于数组索引是从0开始,所以导致数组索引总是比字符位(第3位字符对应数组索引为2)少1&

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值