花了大概3天時間,了解,理解,推理KMP算法,這里做一次總結!希望能給看到的人帶來幫助!!
如果你覺得有幫助,歡迎分享給其他人!送人玫瑰手有余香!
歡迎留言,哪怕一個字,大家的鼓勵就是我寫作的動力!
如果你覺得寫的很爛,請告訴我哪里寫的不好,我盡量調整!
1.什么是KMP算法?
在主串Str中查找模式串Pattern的方法中,有一種方式叫KMP算法
KMP算法是在模式串字符與主串字符匹配失配時,利用已經匹配的模式串字符子集的最大塊對稱性,讓模式串盡量后移的算法。
這里有3個概念:失配,已經匹配的模式串子集,塊對稱性
失配和隱含信息
在模式串的字符與主串字符比較的過程中,字符相等就是匹配,字符不等就是失配;
隱含信息是,失配之前,都是匹配。
在主串S[0,100]中查找模式串P[0,6],從下標0開始查找,在下標為5的位置失配,記為P[0,5]失配,則有
P[5]!=S[5],又有S[0,4]=P[0,4]
則P[0,4]都是匹配的!
已經匹配的模式串子集
接上一例,模式串是P[0,6],而P[0,4]都是匹配的,所以,已經匹配的模式串子集有
Pcs={ P[0,4],P[0,3],P[0,2],P[0,1],P[0] }
2.塊對稱性
什么是塊對稱性?
塊對稱性,就是字符串前綴,后綴重疊;
比如: a b c d a b c
前綴:除了最后一個字母外,所有的前綴子集;
如: a,ab,abc,abcd,abcda,abcdab
后綴:除了第一個字母外,所有的后綴子集
如: bcdabc,cdabc,dabc,abc,bc,c
這里前綴abc和后綴abc重合
可以把這個重合看做,相對於綠塊對稱,所以叫它塊對稱性
塊對稱有很多種;比如:
咦?大家都在一水平排,怎么有一個飛起來了?
飛起來那個將在利用最大快對稱性 小節講解。
塊對稱性有什么特點?
特點:擁有塊對稱性的字符串至少有2塊對稱重合的的部分;
分析,對稱是修飾,重合是關鍵。而且重合的是前綴和后綴。
如何利用塊對稱性?
模式串如圖,如果模式串和主串Str匹配的過程中,在l這失配即P[0,7]失配,你會怎樣?
分析,
第一,模式串的P[0,6]和主串放入S[0,6]是完全匹配的
第二,P[0,6]串是塊對稱的!
因為P[0,6]剛好有塊對稱性,我可以把前綴abc移動到后綴abc的位置,然后讓d與主串去匹配,這樣就利用快對稱性了對吧?
總結,可以在P[7]失配時,看失配字符的最大前綴P[0,6]是否有塊對稱性,如果有,我們就可以向右移動模式串,讓左邊的重合前綴移動到右邊的重合后綴,再讓模式串和主串比較!
利用最大塊對稱性?什么意思?
什么是KMP算法小節里,說KMP是在模式串與主串匹配失配時,利用已經匹配的模式串子集的最大塊對稱性,盡量讓模式串右移!這里的利用最大塊對稱性是什么意思?
這里利用最大塊對稱性意味着可能發生遞歸!
把上個案例的d換成k,如下圖:
KMP算法會預先計算出模式串所有前綴子集中哪些前綴有塊對稱性,在這些有塊對稱性的前綴的后一個字符失配時,利用其塊對稱性;
比如本例中P[0,6]有塊對稱性,那么在P[0,7]也就是l失配時,
會先利用P[0,6]的塊對稱性,即P[0,2]和P[4,6]相遇於字符P[3]塊對稱,
如果不行,會看P[0,2]塊對稱重合的部分有沒有塊對稱性,
有,就利用;以此類推,一直遞歸到沒有塊對稱性為止。
塊對稱長度的意義-編程
第一次移動中,3是什么?塊對稱重合長度,也是下次開始比較的位置!
第二次移動中,1是什么?塊對稱重合長度,也是下次開始比較的位置!
3.next數組推導-計算塊對稱性
單獨的塊對稱性是沒有意義的,塊對稱性必須結合上失配,才能利用塊對稱性!
所以,應該計算出Pattern所有前綴子集失配時的塊對稱性!放到一個叫next[]數組的地方!
如何計算呢?
next數組是計算失配時的塊對稱性,
當第1個字符失配時,壓根就沒有前綴后綴的說法,所以有next[0]是不存在塊對稱性的,記為next[0]=-1;
當第2個字符失配時,它的子集只有1個字符,也是沒有前綴后綴,沒有塊對稱性,所以記為next[1]=0;
再看圖,對於值k,已有p0 p1, ..., pk-1 = pj-k pj-k+1, ..., pj-1,則有next[j] = k。
next[j] = k代表了什么呢?
代表在Pj之前,有長度為k的塊對稱性,有2個長度為k的重合部分。
總結一下,前提條件如下:
條件1.next[0]是不存在的,next[1]=0;
條件2.對於下標值k,已有p0 p1, ..., pk-1 = pj-k pj-k+1, ..., pj-1,則有next[j] = k。
next[]數組是從0開始被初始的,如果我們能推導出next[j+1] = 什么,是不是就可以計算出next[]數組? 是吧
下面來推導next[j+1]
已知:
p0 p1, ..., pk-1 = pj-k pj-k+1, ..., pj-1,==》 next[j] = k
如果pk與pj匹配,
則有p0 p1, ..., pk-1,pk = pj-k pj-k+1, ..., pj-1pj,==》 next[j+1] = k+1;
原來有2個長度為k的對稱重合部分,pk與pj匹配后,2個長度為k對稱重合的部分又有了1對字符重合,所以有next[j+1]=k+1;
再看圖,next[j]=k,當pj失配時,下一次用pk去和主串匹配;所以next[j]的實際意義是,當pj失配時,下一次應該用哪個字符去和主串匹配!!
條件3.next[ ]數組的值就是當次失配時,下一次匹配的位置!
如果pk與pj不匹配,next[j+1]=?
next[j+1]的實際意義是,p[0,j+1]的pj+1失配時,p[0,j]的塊對稱重合長度,也是下一次匹配時應該用模式串的哪個字符與主串匹配,哪個字符的下標就是next[j+1]。
具體詳參塊對稱長度的意義-編程
下一次用哪個字符比較呢?
設a1=p0 p1,...,pk-1,a2=pj-k pj-k+1,...,pj-1;a1==a2
當pk與pj不匹配時,不能用a1替換a2,如圖綠叉;
因為a2是離與主串最近的部分,所以這時候應該分析a2是否有塊對稱性,
如果a2有塊對稱性,那么a1也有塊對稱性,如圖綠框;
所以,這時應該分析p[0,k]的塊對稱性,也就是next[k]。
設x1與x2關於綠框對稱;
x3與x4關於綠框對稱;
那么把x1移動到x4的位置,是不是就可以最大利用上;
所以next[j+1]=next[k];
總結一下
If ( p[k] == p[j] ) next[j+1]=k+1
else next[k+1]= next[k]
4.參考文獻
https://blog.csdn.net/v_july_v/article/details/7041827
http://www.codeceo.com/kmp-next-array.html
https://www.zhihu.com/question/21474082 next數組推導
https://blog.csdn.net/yearn520/article/details/6729426 next數組推到原則
KMP中,計算目標查詢串T的next[]數組是關鍵;
https://zhuanlan.zhihu.com/p/24274982
https://blog.csdn.net/yearn520/article/details/6729426
http://www.cnblogs.com/c-cloud/p/3224788.html
https://zhuanlan.zhihu.com/p/24649304