KMP 算法
KMP 算法是一种快速将模式串与主串匹配的算法。
以下面的字符串为例:
比较 | ↓ | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
主串 | A | B | B | A | B | B | A | B | A | B | A | A | A | B | A | B | A | A | A |
字串 | A | B | B | A | B | A | A | B | A | B | A | A |
KMP 算法做了这样一件事:
先比较第一个字母,A==A,「比较指针」后移一位,然后比较第二个字母,也相等……一直到 ABBAB==ABBAB。当比较第 6 个字母时,发现 B 不等于 A。于是,在这个时候选择研究之前匹配成功的 ABBAB。我们要找这个匹配成功的子串的最长的相等的前缀和后缀,在这个例子中是 AB,即 (AB)B(AB)。于是,我们将整个模式串后移,将之前的前缀移动到后缀的位置,接着和主串比较。即:
比较 | ↓ | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
主串 | A | B | B | A | B | B | A | B | A | B | A | A | A | B | A | B | A | A | A |
字串 | A | B | B | A | B | A | A | B | A | B | A | A |
接下来接着比较主串和子串,当出现不同时还是找最长相同前后缀,当比较指针到子串末尾,或子串在移动后超出了主串末尾时,比较结束,返回成功或失败。
上面是比较形象化的描述,当我们仔细看模式串时,会发现,在和主串对比前,可以对模式串进行预处理。以 ABABAAABABAA 为例,
- 当第 1 个字母 A 与主串不匹配时,将 1 号位与主串下一位比较。
- 当第 2 个字母 B 与主串不匹配时,最长相同前后缀长度为 0,1 号位与主串当前位比较。
- 当第 3 个字母 A 与主串不匹配时,最长相同前后缀长度为 0,1 号位与主串当前位比较。
- 当第 4 个字母 B 与主串不匹配时,最长相同前后缀长度为 1,2 号位与主串当前位比较。
- 当第 5 个字母 A 与主串不匹配时,最长相同前后缀长度为 2,3 号位与主串当前位比较。
- 当第 6 个字母 A 与主串不匹配时,最长相同前后缀长度为 3,4 号位与主串当前位比较。
- 当第 7 个字母 A 与主串不匹配时,最长相同前后缀长度为 1,2 号位与主串当前位比较。
- ……
我们发现,除第一个字母外,当其他的字母与主串不匹配时,如果最长相同前后缀长度为 ,则 x + 1 号位与主串当前位比较。
我们将第一个字母对应的指令取 0,其他的取最长后缀长度 +1,得到 next 数组:[0, 1, 1, 2, 3, 4, 2, ...]
。
这样在比较的时候调用 next 数组即可。
值得注意的是,查阅资料后发现大部分 next 数组都是从 1 下标开始保存的,0 下标一般存储数组长度。
以 CF535D 为例,给出题解如下:
1 |
|
评论