KMP 字符串匹配算法

Posted ybw777

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP 字符串匹配算法相关的知识,希望对你有一定的参考价值。

KMP 算法是一个高效的字符串匹配算法,由Knuth、Morris、Pratt三人提出,并使用三人名字的首字母命名。在KMP之前,字符串匹配算法往往是遍历字符串的每一个字符进行比对,算法复杂度是O(mn)。而KMP算法通过预处理能够把复杂度降低到O(m+n)。

KMP算法

假设给定一个字符串 1 ABCABCABDEF,现在需要搜索字符串 2 ABCABD 在字符串 1 中出现的位置。从 0 位置开始比对,到位置 5 时发现字符不相同,字符串 1 的字符为 C,字符串 2 的字符为 D。接下来如何继续比对呢?KMP 算法的核心就在于这里。考虑到字符串 2 中有两个 AB 重复出现,因此可以把第一个 AB 移动到第二个 AB 处继续比对。这个移动过程就是利用了已经匹配的字符信息,直接将字符串前移 3 位提高了比对效率。

技术图片

 

假设给定一个长度为 n 的字符串 O ,查找长度为 m 的字符串 f 在 O中出现的位置,如下图所示(图片来自网络)。

技术图片

 

当比对到第 i 个字符不相等时,需要把字符串 f 向前移动继续比对,KMP算法通过计算最大公共长度来移动。当满足如下条件时,f 可以前移 k 位继续比对。

  • 字符串 A 是 f 的一个前缀;
  • 字符串 B 是 f 的一个后缀;
  • 字符串 A 和字符串 B 相等。

KMP 算法的核心即在于求解 f 中每一个位置之前的字符串的前缀和后缀的最大公共长度。注意,这个最大长度不包括字符串本身。当比较到第 i 位置时,如果不相同,而此时最大公共长度为 j,则 f 前移的距离为 k = i – j 。

最大公共长度的计算

前缀是除了最后一个字符的子字符串,后缀是指除了第一个字符的子字符串。对于字符串 ABCA,前缀有 A、AB、ABC,后缀有 A、CA、BCA,相同的前缀后缀只有 A。最大公共长度是指当前位置前面的字符串相同前缀后缀的最大长度,使用 next 数组表示。根据这个规则,前面的字符串 2 ABCABD 的 next 数组如下表格所示。对于长度为 m 的字符串,next 数组的长度为 m + 1。显而易见,next[0] = next[1] = 0。

技术图片

 

已知 A3 = A0,next[4] = 1,计算 next[5] 时只需要比对 B4 = B1 则 A3B4 = A0B1,next[5] = next[4] + 1 = 2。

技术图片

 

已知 A3B4 = A0B1,next[5] = 2,计算 next[6] 时首先比较 D5 ≠ C2 则 A3B4D5 ≠ A0B1C2。如果存在一个以 B 结尾的公共前缀,那么这个前缀一定在 C2 的前面,这个前缀的长度为 next[next[5]] = 0,因此 C2 的前面没有这样的前缀,并且 D5 不等于 A0,next[6] = 0。

技术图片

 

假设我们现在已经求得 next[1]、next[2]、……、next[i],现在要求next[i+1]。可以看出,如果位置 i 和位置 next[i] 处的两个字符相同,则 next[i+1] = next[i] + 1;如果两个位置的字符不相同,可以继续向前搜索,获得其最大公共长度 next[next[i]],然后再和位置 i 的字符比较,直到能最终确定结果。(图片来自网络)

技术图片

 

根据上面的分析,不难写出求解 next 数组的代码如下。

技术图片

 

字符串匹配

字符串匹配的过程和求解 next 数组的过程类似。假设搜索字符串 f 在字符串 O 中出现的位置,f 的下标为 j,O 的下标为 i。如果 O(i) = f(j),则 j = j + 1,继续比较 f 中的下一个字符;如果 O(i) ≠ f(j),则 j = next[j],继续比较 f 中位置为 next[j] 的字符,相当于 f 前移了 i - j 位。当 f 的下标 j 移动到末尾时,说明匹配成功,此时可以算出第一次出现的位置是 i - j。

如下图所示,假设 O 为 ABCABCABDEF,f 为 ABCABD。O(4) = f(4),下一步继续比对 O(5) 和 f(5) 即可;O(5) ≠ f(5),则 f 的下一个比对字符位置为 next[5] = 2,下一步继续比对 O(5) 和 f(2),相当于 f 前移了 5 - 2 = 3 位。当比对到 O(8) = f(5) 时,f 已经比对到末尾,匹配成功,此时算出 O 中出现的位置为 8 - 5 = 3。

技术图片

 

根据上面的分析,不难写出匹配字符串的代码如下。

技术图片

 

技术图片

以上是关于KMP 字符串匹配算法的主要内容,如果未能解决你的问题,请参考以下文章

字符串匹配---KMP算法

字符串匹配----KMP算法

经典字符串匹配算法——KMP算法

字符串匹配之KMP算法

字符串匹配算法——KMP算法

KMP--字符串匹配