意图理解——KMP算法

想写一个算法思路(意图)的系列,从KMP算法开始吧,不讲代码,只讲”为什么要这么想,这么写“,看网上这么讲的还没见到,自己想写的还是必须自己写啊~

KMP一直看书不明白的,看视频真的有帮助,老师会自然而然地说出思路而非书上那般生硬。
B站,严蔚敏奶奶视频教程


一、kmp的目标:

1,防止i指针回溯。

需要重新匹配时,其实前面的已经匹配成功,问题可以转化为模式串的自比较,从而省去i指针的回溯。

2,让j指针回溯得尽量少。

模式串的前缀、后缀最长重复位数可以代表需要跳过几位。


二、一个实例

一位一位比较时
遇到主串i指针的字符 与 模式串j指针的字符 不匹配时。

-------i
abaabcabbbbb
abaabcac
-------j

发生了i指针回溯,同时产生了已经成功匹配序列的错位

-i
abaabcabbbbb
-abaabcac
-j

再一位一位比较……

--i
abaabcabbbbb
--abaabcac
--j
---i
abaabcabbbbb
--abaabcac
---j

突破点是已经成功匹配的字符串,错位后,除了一些特殊情况,必然不能匹配!

那个“特殊情况”就是前缀与后缀的重复,同时,匹配成功的主串、模式串的部分是相等的! 这样next数组仅仅交给模式串就等于主串、模式串都遵守了!
——回到第一步那里,接着可以直接进行下一步:j回溯到模式串的b(从第一步的c)。

-------i
abaabcabbbbb
------abaabcac
-------j

三、原理要点

0,明白什么不用比较,什么还需比较
1,基于已经成功匹配的字符串(已知匹配成功的位数)
2,i回溯会导致已经匹配成功的串错位(主串与模式串),如何防止i指针回溯导致的浪费?——除了一些特殊情况,错位必然不能匹配!
3,特殊情况——只用考虑【已经匹配成功的部分主串(也就是部分模式串!匹配成功的部分代表它们完全一致!)】的错位是否会有”重复“
4,错位时,模式串前缀后缀的重复可以避免重新匹配(模式串与模式串——next数组)
5,next数组标记的有关于当前字符子串前缀、后缀最长重复长度,也就是可以不直接退回j串第一个字符的可以少回溯的重复部分。


四、通过观察就能解出next数组值的方法!!!

以下摘自:next数组两种求法

1)算出每一个字母前缀后缀的最大公共子串长度(下一步会把最后一位移走,所以最后一位可以不算)

Pababaca
前后缀最大公共子串长度001230*

关于前缀后缀放张图,下图引自:https://www.cnblogs.com/zhangtianq/p/5839909.html
在这里插入图片描述

2)最大公共子串长度整体向后移动一个长度,最前面的元素值填 -1,即为 next 数组的第一版本

Pababaca
next 数组第一版-1001230

3)(如果你需要的 next 数组第一个值为 -1,第二步就是结果了)next 数组的每一个值分别+1,即求得 next 数组。

Pabaabca
next 数组第一版0112341

五、理解next

next[j] 内的值不代表j之前的子串前后缀的最大长度
而是“当模式串中第j个字符与主串相应字符‘失配’时,
在模式串中需要重新和主串中该字符进行比较的字符的位置”。
这就是第四节方法中求出前后缀以后,为什么还要进行后续的操作

书上的算法不过就是如何实现第四节的方法罢了(但是教材可没告诉我那么简单的观察求next数组的方法啊!!)
书上的算法不过就是如何实现第四节的方法罢了(但是教材可没告诉我那么简单的观察求next数组的方法啊!!)
书上的算法不过就是如何实现第四节的方法罢了(但是教材可没告诉我那么简单的观察求next数组的方法啊!!)

教材定义图引自:https://blog.csdn.net/qq_37969433/article/details/82947411
在这里插入图片描述
*注:教材上的”1“是[其他情况],不是[”不匹配时“]
这图上的精确的数学语言看着就让人头疼,不如按着公式试试几个例子。

这是严蔚敏教材P81的next数组值

abaabcac
01122312

先用观察法求一遍验证一下(卧槽,竟然如此简单,太感谢那位博主了!链接就在第四节第一行里)
_abaabcac
_0011201*
-10011201
_01122312

验证公式:我们取第4位的”a“,则这个a的next[4]的值是”k=2“,[1到2-1]=[4-2+1到4-1]即【1到1】=【3到3】即 [a]=[a]。
这也应当是”最长前后缀重复长度“

abaabcac
---2----

验证公式:我们取第6位的”c“,则这个a的next[6]的值是”k=3“,[1到3-1]=[6-3+1到6-1]即【1到2】=【4到5】即[ab]=[ab]。
这也应当是”最长前后缀重复长度“

abaabcac
-----3--

下面是回溯j指针的实例。
【现在是f比a】同时,在匹配错误时跳过多少?

---i
abafbcabbbbb
abaabcac
---2----------------next

回溯至2【现在是f比b了】(j=next[j],就是j赋值当前位置的next数组的值,也就是下一步的位置(已经算好了跳到哪里))

---i
abafbcabbbbb
--abaabcac
---1-----------------next

回溯至1(回溯到头都没有,之前的整串又配不上,GG,真匹配不上了)
这里发现了又匹配到了f对a,这个涉及”对KMP算法的一种改进“,书上有。

---i
abafbcabbbbb
---abaabcac
---0------------------next
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

超自然祈祷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值