KaiSpace
tech

KMP算法

KMP算法补充解释

看本文前请先通读算法竞赛进阶指南,本文仅为少许补充。

书中引理解释

我们先来定义“候选项”:以i为结尾的后缀j0j_0个和前缀j0j_0个数相同,则next[i]的值可能是j0j_0,也就称j0j_0是next[i]的候选项。

引理内容

j0j_0是next[i]的“候选项”不存在“候选项”在next[j0j_0]到j0j_0之间。推论:若next[i]=j0j_0,也就是以i为结尾的后缀j0j_0个和前缀j0j_0个数相同,那么得出只有j = j0j_0或next[j0j_0]或next[next[j0j_0]]或……时,以i为结尾的后缀j个和前缀j个数相同。

image-20250407213327279

证明:

我们沿用书中的反证法,假设在j0j_0和next[j0j_0]中存在j1j_1,其中j1j_1也为“候选项”。

配图解释:

假设next[i] = j0j_0

(1)为1~i的完整字符串。(2)为以i为结尾的j0j_0个字符。(3)为以i为结尾的next[j0j_0]个字符。(4)为以i为结尾的j1j_1个字符。

(5)为以1为首的j0j_0个字符。(6)为以j0j_0为结尾的next[j0j_0]个字符。(7)为以1为首的next[j0j_0]个字符。(8)为以1为首的j1j_1个字符。

已知:(2)和(5)相同,(3)和(7)相同,(6)和(7)相同。

所以(3)和(6)相同。

假设(4)和(8)相同,那么(8)在(5)上肯定有对应后缀串,又由于j1j_1 > next[j0j_0],所以next[j0j_0]应该为j1j_1,矛盾。所以不存在j1(j0,next[j0])j_1 \in (j_0, next[j_0]),使j1j_1为候选项。

这个引理有什么用?

如果next[i] = j,则next[i - 1] = j - 1,也就是说如果以i为结尾的j个字符和以1为首的j个字符相等时,必有以i - 1为结尾的j - 1个字符和以1为首的j个字符相等。contrapositive后,只有next[i - 1] = j - 1,才可能next[i] = j。

也就是next[i] = argmaxxnext[i1]=j1A[i]=A[j]\underset{x}{\operatorname{argmax}}next[i - 1] = j - 1且A[i] = A[j]

这样我们对于next[i]求取可以做到很好的剪枝,只需要查询少量可能的j。且我们只需要找到第一个符合的即可,所以A自匹配算法复杂度为O(N)。

知道了next后如何在B中查找A?

A中附加了很多退回信息,这种信息相当于钩子一样。一般而言,一旦不匹配就相当于滑倒底端,从1开始再一个一个匹配。加入了next之后,相当于在半当中被挂住,可以从中间开始继续匹配

Comments

No comments yet.