kmp算法的实现
假设现在有如下场景,有一字符串abcdefg,有另一字符串efg,我们该如何快速从字符串中寻找其子串呢?
不难想到我们有一个显而易见的算法,可以先从主串的第一位开始遍历,将a与e比较,此处明显不匹配,继续讲b与e比较,不匹配,继续一直跳过,直到e和e匹配,我们就将子串和主串各自往下移一位。然后发现f和f是匹配的(假如此处f不匹配会怎么样?例如此时主串为abcdeug,子串不变。那么e和e匹配,但是u和f不匹配,此时就将e和u再次匹配,显然此处也是不匹配的,就继续向下知道一直合适位置。
显然这个算法十分复杂,每次都要进行重复的便利,那么有什么办法可以减少字符串匹配的次数呢?我们有如下场景:
主串:aaaaaaaaaab 子串:aaab,如果按照上面所述的方法,这个匹配显然得每次都进行到子串的最后一位然后匹配失败,再次进行匹配,但是仔细一想,每次都匹配过a了,就是已经做过很多次正确的匹配最后一次匹配失败,那么按理来说我们可以跳过几个已经匹配过的数字然后继续进行匹配?那么该跳过几个字符呢?此时我们就引入了kmp算法中的next数组,这个数组存储了你应该跳过的字符的个数。我们在匹配失败的时候会看最后一个匹配的字符所对应的next数值。
我们先忽略next数组的计算,假设我们已知next数组的大小该怎么进行计算呢?以下是代码实现:
next数组对于不同的字符串显然有不同的数组,所以我们该思考怎么进行next数组的计算。
假设有如下场景
abbabbababaaababaaa
abbabaababaa,此处我们在第六位发现不匹配。在第六位之前我们有字符串abbab,对于这个2字符串来说,我们可以找到两个匹配的公共前后缀ab,那么此时kmp算法就教我们叫子串后移到
abbabbababaaababaaa
abbabaababaa,注意看此处的对齐。将前面三个字符跳过了,此时我们可以在进行一次刚才的操作,再次匹配再次跳过。。。以此类推。(前后缀不能等于子串长度不然没有意义),那么此处next数组的大小为最大公共前后缀长度加1,第一位因为前面没有数字固定为0.
例如abaaab,0,1,1,此时为aba,所以为2,再后abaa,2,abaaa,2,abaaab,3,所以next数组为0112223.