KMP算法原理推导

看教材上的解释差点看哭,但是B站视频又不解释透彻,以下是教材上的KMP原理推导,我尽量解释清楚。
很多文章是一开始就说找最大公共前后缀,我建议先忘掉这个概念,拒绝意会,用数学方法彻底搞清。(看到数学别怕,它最无懈可击)
举例子说明:

     主串:a b a b c a b c a c b a b
     
   模式串:a b c a c

要找到主串中有没有和 模式串一模一样的字串(专业称呼:字串的定位运算,模式匹配,串匹配),首先说下暴力解法,也叫BF算法,就是模式串的第一个和主串的第一个开始一个个比较一样不,不一样就把模式串往后挪一位再比。计算机嫌时间多的话就用这个算法吧。

主要讲KMP算法,开始:
设主串为 a1a2.......an
模式串为 b1b2...bm
当主串中的第i个字符与模式串中的第j个字符不同时,ai需要和模式串中的第几个字符比较呢?

BF算法直接让a i 与模式串中的第一个字符b 1开始匹配,说它暴力就是暴力在这里,要是主串是aaaaaa…ab(此串有十万个a)模式串是ab,用BF,循环个十万减一再乘以2 次,嗯,祝电脑好运

既然没必要每次和模式串的第一个比较(前面已经匹配过的结果是可以有用的)那主串中不匹配的a i要和模式串中的第几个字符再进行比较呢
这是未知数,但是数学最常用的手段就是设未知数.

我们设主串中不匹配的a i需要与模式串中再进行比较的字符是模式串中的第k个字符b k
容易得到
b1b2…b(k-1) == a(i-k+1)a(i-k+2)…a(i-1) [式子一]
(需要比较ai 与bk,它们之前的字符自然都匹配)
又由当主串中的第i个字符与模式串中的第j个字符不同时(k<j)这句话可得到
a(i-k+1)a(i-k+2)…a(i-1) ==b(j-k+1)b(j-k+2)…b(j-1) [式子二]
由式子一式子二可得
b1b2…b(k-1) ==b(j-k+1)b(j-k+2)…b(j-1) [式子三]
所以,如果模式串中存在式子三这样的两个子串,那么当匹配过程中,主串中第i个字符与模式中第j个字符不同时,仅需将模式串向右滑动至模式中第k个字符和主串中的第i个字符对齐. 此时,模式串的长度为k-1的 b1b2…b(k-1)子串必定与主串ai前面的长度为k-1的子串a(i-k+1)a(i-k+2)…a(i-1)相等,所以,匹配仅需从模式串中的第k个字符与主串中的第i个字符开始,依次向后进行比较

下面上一张图来表示一下:
在这里插入图片描述
红色代表相同的部分

接下来,就是next函数的主场了
我们令next[j]=k,那么next[j]的含义就是当模式串的第j个字符与主串的相应字符不一样时,模式串中需要再次与主串的该字符进行比较的字符的位置

next[j]= 0 (j=1 ,模式串第一个就和主串不一样,第一个字符前面自然没有字符了,所以只能拿第0个字符去和ai对齐,也就是没有字符去和它对齐,也就是进行b1与a(i+1)的比较)

next[j]=max{k|1<k<j且有b1b2…b(k-1) ==b(j-k+1)b(j-k+2)…b(j-1) }
(即k等于模式串ai前面的字符串的最大公共前后缀长度加一)

next[j]=1 (k=1,不存在相同的子串,下一步进行b1与ai的比较)

举个例子

j 1 2 3 4 5 6 7 8
模式串 a b a a b c a c
next[j] 0 1 1 2 2 3 1 2

综上,KMP算法与BF十分相似,不同之处在于:当匹配过程中产生"失配"时,指针i不变,指针j退回到next[j]所指示的位置上重新进行比较,并且当指针 j 退至0时,指针 i 和指针 j 需同时加一,即若主串的第 i 个字符和模式的第一个字符不等,应从主串的第i+1个开始匹配

本文绝大部分思路是严蔚敏老师的数据结构这本书中的,我只是懂了后自己来讲一遍,同时加入一些自己的理解和体悟.B站上的两位UP主天勤率辉和正月点灯笼的KMP解释视频可以去看看,虽然感觉一到精妙处就不讲清楚了(可能我比较事多),但是动态图和过程都画得很好,而且正月前辈的也挺详细的,很能帮助理解

下一篇博客写KMP算法的代码,给我自己加油,嗯.

おすすめ

転載: blog.csdn.net/heipao17/article/details/115218572