KML 算法用来处理字符串匹配的问题。核心思想是当出现字符串不匹配时,根据之前已经匹配的文本内容,避免从头再去做匹配。
举例:
字符串,原始字符串,模式串是否属于字符串的一部分;
模式串,字符串的子串,用来匹配的。
对应字符串与模式串如下:
字符串:aabaabaafa
模式串:aabaaf
暴力破解方式为2层循环,一个字符一个字符交替进行匹配,此时时间复杂度为 n * m。
使用KML算法匹配,从第一个开始匹配,匹配到b != f的时候,不是从头开始匹配,而是从模式串的b开始往后匹配,可以一直匹配的末尾,字符串匹配到最后一个的下标减模式串的长度(8-6=2),即是结果
概念
能更清晰说明白KML算法,需要厘清几个概念
- 前缀:包含首字母,不包含尾字母的所有子串
- 后缀:包含尾字母,不包含首字母的所有子串
- 最长相当前后缀:字符串的前缀后缀相当的子串中,最长的子串
- next数组:存放遇到冲突后,回退下标,计算方式为最长相当前后缀长度
next数组
- 赋值内容:直接存最长相当前后缀长度,开头存负一整体右移,最长相当前后缀减一
- 计算逻辑:
- 从第一个子串开始逐个循环
- 前一位子串的最长相当前后缀的基础上分析,当前子串的最后一位=前一个最长相当前后缀长度所在下标的字符,则当前子串的最长相当前后缀加一,因为前面的在上一步已经判断过了
- 当前子串的最后一位 != 前一个最长相当前后缀长度所在下标的字符,因为上一个最长相当前后缀可知前面的比较结果已经知道了,所以不用全部回退,只需要找到前一个下标的next数组中的最长前档前后缀的长度,回退到那个位置继续比较,直到相当或到头,记录最长相当前后缀在next当前的下标
- 方便理解的几个模式串例子:aabaaf-010120、afbafaf-0001212、afbafafbafcaf-0001212345012
实现示例
1 | /** |