回溯問題
上一講 BruteForce算法的結尾中,我們提到了BruteForce算法的缺點,其中一條就是回溯問題,導致效率降低。
什么是回溯呢?
假設目標串S = "aaaaaaaab" ?T="aaab" 當我們利用BruteForce算法時,前三次的"aaa"的比較是毫無意義的,換言之,就是影響了效率。
KMP算法
為了提高效率,因此我們要使用KMP算法。KMP算法是一種改進后的算法,并且是由D.E.Knuth、V.R.Pratt和J.H.Morris同時發現的,因此稱之為KMP算法。
其基本思想為:每當匹配過程中出現字符串比較不等時,不需要回溯指針,而是利用已經得到的“部分匹配”結果將整體模式向右“滑動”盡可能遠的一段距離,繼續進行比較。
如何實現這個思想,換言之如何判斷得到部分匹配結果?這里我們需要完成KMP算法中的第一步也是核心步驟:模式串求最大真子串。
1.模式串求最大真子串
舉個栗子
當J = 0 時 按照上面的思維導圖公式,next[ j ] = -1
當 J = 1 時,next[ j ] = 0,因為我們想求模式串的最大真子串,而這個最大真子串是指不包含當前位置編號的字符,而是它前面的字符所構成的字符串里有沒有最大真子串,因為 J = 1 時,模式串只有一個 a ,所以構不成最大真子串,因此屬于其他情況,next[ j ] = 0
當 J = 2 時,next[ j ] = 1 ,因為當前位置編號的字符前面有2個 a,a 與 a 相等,滿足我們的公式,并且他們的最大真子串長度為1(因為一個字符的長度為1),所以,記 next[ 2 ] = 1
當 J = 3 時,next[ j ] = 2,因為同理,當前位置編號的字符前面有3個 a,第一個a與第二個a構成的字符串==第二個a與第三個a構成的字符串,長度為2,所以,記next[ 3 ] = 2
一次類推,最后的結果如圖所示,不再贅述了。下圖為另一個例子,大家可以對照答案看看有沒有掌握好。
PS:當 J = 8 時 ,應比較前七個字符中是否有最大真子串,我們發現只有第一個a 和 第七個 a 滿足公式,因此next[ 8 ] = 1
最大真子串的實現代碼!
最大真子串的算法需要理解,同學們跟著代碼的邏輯思路對照圖表理解效果更佳。
2.KMP算法原理
KMP算法原理:當Si ≠ Tj, 若模式串存在最大真子串,可將模式串T按照 k=next[ j ] 的值向右滑動,然后比較 Si 和 Tk ,若仍有Si ≠ Tk,則模式串T按照新的 k=next[ j ] 的值向右滑動后比較。這樣的過程一直進行到 k = next[ k ] = 0,此時若Si ≠ T0,則模式串T不再向右滑動,隨后比較Si + 1 和 T0 。
原理很枯燥而且很難理解,但還是要寫,顯得很高大上 ^_^ 大家能不看就不看吧~
我們還是根據例子和圖表來進行理解!
舉個栗子 例如:主串 S = "aaaaaaab" ?子串 = "aaaab" 采用KMP的模式匹配過程。
對應的最大真子串集如圖。
首先一次進行比較,發現aaaa全部相等,當 b 時也就是J = 4時,由于不匹配,所以整體向右滑動一格,并且比較子串的第四個a,以此類推,最后完全匹配時,僅需要10次,大大提升了效率!!!
KMP實現代碼!
兩個方法都寫在了KMP類里,同學們依然要跟著代碼分析一遍,重點是對于最大真子串的理解。
大家可以寫一個測試類,聲明兩個字符串,看一看匹配的輸出結果~
輸出結果為3哦!
KMP算法總結
KMP算法的效率是很高的,遇到相關算法題時也應該使用該算法進行解題,多多熟練也是好的嘛!
下一講我們將會講一個有意思的小游戲---彩票機選的算法與實現 期間用到的相關知識 我會整理在一節中 內容可能較多哦!
PS:有什么問題或者不解的地方可以評論,我都會一一就行回復的,如果有錯誤或者言語不明的地方,還請大神多多指點!