KMP算法

97 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

KMP算法又叫字符串匹配算法,它是指在一个字符串A里面寻找字符串B是否有匹配。

非常简单的一个做法是,二重循环一个一个的比较,如果匹配超过,继续,匹配失败i++。

如图,这个时候i,j对应的值相等,匹配,那么ij同时++ image.png

如果i,j下标对应值不相等,那么j归0,i变成上次遍历开始的下一个位置。 image.png image.png image.png

直到这样,依次匹配,就可以得到答案了

image.png

但是这样做的话,最多寻找m-n个位置。 看上去还是还想,但是如果字符串特殊,那么就很耗费时间了 比如:str1=11111111111111112;str2=12那么就会一直循环判断(时间复杂度O(m*n))。

那么可以优化吗?

KMP算法认为,既然失配部分前面的字符(上图的bc)已经比较过了,那么就不应该再比较一次。所以需要考虑前面匹配过字符的最长匹配,

如果在i位置发现不符合,那么把str1前面的前缀和后缀找出来,在str1里面最长相关前缀第二个开始比较

为什么加速了?

image.png image.png

其实就相当于,第一次,我们需要从i=0开始寻找,当遇到不匹配时候,从i=3开始寻找。i=3之前,一直做过匹配,不能匹配成功(如果存在匹配成功,那么最长前缀后缀一定有它。),并且第一次不能匹配点在i=3,所以省掉了乘法验证过程,直接从不能错误点开始寻找,做了加速。

str1: abba eyu abba k

str2: abba eyu abba h

最好一个不同,str2最长前缀abba

那么从str1的第二个abbc开始比较

str1: abba k

str2: abba eyu abba h

有不同,最长前缀 a

ba K abba eyu abba h

依次类推

算法实现思路

1.怎么寻找前缀后缀最大匹配的匹配?

前三个位置人为规定,位置0,是-1,位置1是0,位置2是0.位置3使用前面的计算。因为i位置最长前缀,需要求i-1的前缀,

image.png

如果i位置和第一个问号相等,那么最长匹配变成8,如果不一样,那么就往前跳

image.png

主题部分:

先把字符串都变成字符数组,然后定义比对位置,并且找到前缀匹配地方。如果当前字符数组相等,都后移,如果不相等,就从第二个前缀开始。

image.png