我们要关注的重点是什么
假设有两个字符串:
1. aaba
(主串)
2.aaabcab
(模式串)
我们要用1去匹配2,第第一次匹配如下
1在匹配到第3个字符串的时候发生了错误,一般情况下我们需要2串往前移动一次就行
这一次匹配,1是从第二位开始匹配的,我们要关注的就是主串1上一次匹配失败的位置是什么,主串新的一次匹配是从哪个一个位置开始的;这两个位置就是重点
我们在进行匹配的时候,控制匹配哪个字符是依靠指针的移动来进行的,指向主串1指针,第一次失败指向第3次,而下一次重新开始的位置是1,指针又移动回去了,每一次匹配失败,都要移到最开始匹配的下一个位置,这个时候,这个移动并不是多余的,但是它是很有规律的,这个规律的发现决定了这个KMP算法是高效的;
这句话是等价的
匹配失败的时候,主串指针往回移动和模式串往前移动是等价的,主串指针需要往回移动,模式串当然也需要往前移动,只不过我们只说一个条件,但是这两个条件都会发生;因为我们并不知道模式串往前移动一次,主串会不会发生匹配;这两个条件的操作都要做;
主串匹配失败,每次往后移动的规律
这个规律就是,假设某一次匹配模式串匹配的是[p1-pn]
,主串是[ph-pj]
这里的p1,pn,ph代表了字符串的位置,p1就是字符串的第一个字符,pn代表第n个字符,用括号[ ]括起来,代表从p1字符到pn字符组成的字符串;
不管哪一次匹配失败,主串的[ph-pj]
这一小段字符串,总是等于模式串的[p1-pn]
,也是肯定属于模式串的
这就是规律,每次往后移动,不都是和模式串[p1-pn]
做比较吗?
如果我们知道模式串的每一个小字符串[p1-pn]
,可能是[p1-p2]
也可能是[p1-p5]
。。。等,这些字符串发生失败了,在主串的[ph-pj]这个区间内,模式串往前移动多少个位置依然可以匹配成功,换言之,匹配失败的主串“i”位置元素与模式串的哪个“j”位置的字符串匹配;我们就可以不用再让主串的指针往回移动了,因为我们已经知道了模式串往前移动后,这个小区间的元素依然是可以匹配成功的,这个小区间是主串[ph-pj]
往前进一位[ph+1 - pj]
;
模式串可能往前移动一次可以匹配成功,移动两次也可以,移动三次也可以,巧就巧在这个字串都是模式串的子串,所以我们可以把所有的情况都求出来,以后不管主串匹配到哪个模式串的位置,我们只需要移动模式串就行了,而不需要在移动主串的指针,因为我们提前知道了移动过后依然可以匹配成功;此时之前说的那句话就不等价了;
剩下的怎么具体求模式串的每个字串的移动位置,我就不写了,有很多详细的步骤,我只是想说一下这个算法巧妙地地方是啥;