今天刚学到kmp算法,开始时觉得玄而又玄,刚才思考了一下,发现明白了其数学原理后,算法本身就很简单了,下面就分析一下其数学原理
首先设串a1,a2,a3,....am为待搜索的串A,b1,b2,..bn为子串B(n<=m)。
先来想一下kmp算法,其中第一步操作就是要找到B所有以b1开头的子串的最大前缀后缀公共元素。这里,我们就以一次匹配的过程为例子,分析为什么要这样做。
假设在匹配了若干次后,我们匹配到了A的子串ap+1,ap+2,,,,,,ap+q和B的子串b1,b2....bq是匹配的,但后面就不是匹配的了。
我们写成如下形式:
a1,a2........ap, b1,b2,......bq-1,bq, ap+q+1,.....am
b1,b2.......bq-1,bq, bq+1........bn
(因为ap...ap+q=b1.....bq,就直接把ap.....ap+q替换为b1,....bq)
为了简便,我们记 b1,b2.......bq-1,bq为子串B1,B1的最大前缀后缀公共元素为b1....br,即b1.....br=bn-r+1,.....,bq。根据算法的做法,这时只需要把B向右移动q-r然后继续匹配就可以了:
b1,b2,....br, br+1,.....bq-r, bq-r+1......bq-1,bq
b1,b2,...............,br, br+1.......,bq
,这说明这时B向右移动任意小于q-r,都不能使下面匹配成立:
b1,b2,....br, br+1,...bk,bk+1,.. ..bq-r, bq-r+1......bq-1,bq
b1,b2, ...............,br, .........br+1.......,bq
(蓝色部分是无法匹配的,即上下蓝色部分不会完全相同)
那为什么就不能匹配成功呢??我们不妨来假设能匹配上,看会发生什么:
假设存在s>r,使得将B右移q-s后,b1,b2,......bs=bq-s+1,bq-s+2,.....bq,即
b1,b2,.......bq-s+1,bq-s+2,.......bq-r+1,bq-r+2,.......bq-1,bq
b1, b2. .............................................bs-1,bs.bs+1,................
蓝色部分是相同的。发现了什么?好像出现了一个比b1....br更大的前缀后缀公共元素b1......bs(s>r),这与b1.....br是B1是最大的前缀后缀公共元素是矛盾的,这说明B1确实不可能在向右移动少于q-r步内再次匹配上,
所以,在下次匹配前,我们只需要先移动p-r使串变成下面就能开开心心地继续匹配了。
b1,b2,....br, br+1,...bk,bk+1,.. ..bq-r, bq-r+1......bq-1,bq
b1,b2, ...............,br, .........br+1.......,bq
差点忘了,我们还要说一下为什么继续匹配时接着从A串的ap+q+1匹配就可以了:
(图片转自csdn《从头到尾彻底理解kmp》,侵删)
由这幅图可以很容易看出,移动后原来匹配过的地方仍然是匹配的,只要继续匹配就可以了。
,这样算法最关键的部分的原理就清楚了,剩下的都是一些操作细节,就不再详述了。
(我相信,在一个月后,当我再看这篇文章时,一定不明白我自己都在说什么了)