简单的模式匹配算法
从主串S的第一个字符起,与模式串T的第一个字符比较,若相等,则继续逐个比较后续字符;否则从主串的下一个字符起,重新和模式串的字符比较;以此类推,直至模式串中的每一个字符依次和主串S中的一个连续的字符序列相等,则称匹配成功,函数值为与模式串T中第一个字符相等的字符在主串S中的序号,否则,称匹配失败,函数值为0。
KMP
若已匹配相等的前缀序列中有某个后缀正好是模式串的前缀,则可将模式串向后滑动到与这些相等字符对齐的位置,主串 i 指针无需回溯,并从该位置继续比较。
子串指针移动位数
可通过子串本身得到部分匹配值表(PM表)
移动位数 = 已匹配的字符数 - 对应的部分匹配值
Move = (j - 1)- PM [ j - 1]
每当匹配失败,就去找它前一个元素的部分匹配值
改进:
将PM表右移一位(第一个元素填 -1),哪个元素匹配失败,直接看自己的部分匹配值,得到 next 数组
Move = (j - 1)- next [ j ]
相当于将子串的比较指针 j 回退到
j = j - Move = j - ((j - 1)- next [ j ] )= next [ j ] + 1
改进:
将 next 数组整体 +1
此时
j = next [ j ]
当子串的第一个字符与主串发生失配时,跳到子串的 next [ j ] 位置重新与主串当前位置进行比较。
求 next 数组
三种情况:
- 模式串第一个字符与主串当前字符不匹配, next [0] = 0
- 若已匹配相等的前缀序列中有某个后缀正好是模式串的前缀,此时可以计算出当前字符不匹配时的下一次比较位置
- 最坏情况,模式串第一个字符与主串第 i 个字符比较,next [ j ] = 1
小技巧
在手算next数组时,next [0] = 0,next [1] = 1,后面的再去依次分析
进一步优化:
若 j 和 next [ j ] 指向同一个字符,则需再次递归,将 next [ j ] 修改为 next [ next [ j ] ]