KMP模式匹配算法

这是数据结构学习过程中遇到的第一个较难的算法,也是一个经典算法,关于字符串的模式匹配问题,相信也是被Java中String类中的模式匹配的方法用在它的方法具体实现中了。

首先要陈述一下问题:
一个主串,一个子串(又称模式),求出子串第一次出现在主串中的位置,这里的位置是主串的第一个字符在主串中的位置,不过这里给了一个初始值pos,要求从主串中第pos个位置开始去匹配。

KMP算法是对暴力匹配算法的改进,所以要先提一下暴力匹配算法的思路:
从初始位置开始,直接去比较,若当前字符相等,则继续比较下一个字符,运气好的话,一次就比完了;若碰到字符不相等的,则相当于一下子回到解放前,前面做的比较都是无用功,要回到主串的初始值位置的下一个位置,继续从子串的第一个字符开始比较,以此类推。

KMP算法的理念追求是希望主串中比较的位置不回溯,在这个理念上,要考虑的问题就是主串中当前比较的位置(当然目前是出现了字符不匹配的情况)在下一轮比较的时候,应该去和子串中的哪一个位置开始去做比较。这里为了叙述的方便,需要引入几个变量来辅助叙述。

比如说当下出现了主串中的Si ≠ 子串中的Tj,要考虑的问题就是下一轮比较的时候,Si和子串中哪一个位置的字符Tk开始比较,显然k是要小于j的,具体等于多少,这是个这个算法最关键最核心的问题。

而这个问题可以大概想象成是一个字符串的前后错位重叠的感觉,一边是从第1个元素往后去找,一边是从第j-1个位置往前去找,看最多能产生多长的匹配,当然也有可能匹配长度为0。这里也不是说在这里匹配得越长就越好,匹配得越长,只能说你下一轮比较的时候稍微省点事,但也不代表你下一轮就能完全匹配成功。如果找到了一个长度k-1的匹配,则下一轮比较的时候Si就是和Tk开始比较;如果匹配长度为0,那Si就和T1开始比较。

这里的想法看似挺厉害,但让人不禁想问一下,你凭什么可以这么做?你这样做为什么是合理的,你主串中的i凭什么可以不回溯,你不回溯的话,你有没有错过一些前面的可能性,就是相比于低效但肯定正确的暴力匹配算法,你有没有漏掉一些情况?或者说这个模式匹配问题最终的答案可能就是你当前i前面的某个位置,那你还不回溯,你有没有可能得出错误的位置结果?

关于这个问题,回答是不会的,不会有漏掉的情况,因为去寻找k = next[j]的匹配过程,其实就包含了对主串中i前面位置的可能性的排查了。假设原始模式匹配问题的答案是主串中第m个位置,m < i,那么根据k = next[j]的寻找过程,在新一轮比较的时候,Si一定不会是和子串中别的位置的字符比较,Si一定会和T(i-m+1)去比较,即k = i - m + 1。

其实这个比较过程从直观上可以想象成两把尺子或者两支笔相互滑动着去比较,去匹配,去配对的过程,还是很形象的,需要一点空间想象力。

================================

以上的叙述都还是朦胧的对问题的描述和对问题的思考,但并没有真正对k = next[j]的求解过程给出一个确定的统一的求解方法。

首先可以肯定的是,next[j]函数的值只和子串本身和j的值有关,和主串无关,因为这里可以想象成上文说的“前后错位重叠”是子串和子串自己的重叠。一旦一个子串确定下来,则它的长度L也就确定下来了,则每一个next[j]事实上都确定下来了,这里 1 <= j <= L。

首先next[1] = 0,模式匹配过程中碰到这样的情况的话,则i和j都要往后加1然后接着去比较。对于j>1的情况,教材中对next[j]的求解是通过递推的方法:
假设next[j] = k,则next[j+1]等于多少?
书中展开了分类讨论:
如果Tk = Tj,则next[j+1]就等于k+1;
如果Tk ≠ Tj,那么问题就复杂了,这就相当于变成了一个新的模式匹配问题,原问题中的子串在这里既充当主串,又充当子串。实际上主串可以理解为"T1T2…Tj",子串为"T1T2…Tk",而现在Tk ≠ Tj,所以要去寻找k1=next[k],如果Tk1继续不等于Tj,则继续找k2=next[k1],依次类推,总可以找到最后的k’,于是next[j+1] = k’,k’可能为0,此时next[j+1]=1。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值