精品伊人久久大香线蕉,开心久久婷婷综合中文字幕,杏田冲梨,人妻无码aⅴ不卡中文字幕

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
KMP算法學習(詳解)

 

kmp算法又稱“看毛片”算法,是一個效率非常高的字符串匹配算法。不過由于其難以理解,所以在很長的一段時間內一直沒有搞懂。雖然網上有很多資料,但是鮮見好的博客能簡單明了地將其講清楚。在此,綜合網上比較好的幾個博客(參見最后),盡自己的努力爭取將kmp算法思想和實現講清楚。

 

kmp算法完成的任務是:給定兩個字符串O和f,長度分別為n和m,判斷f是否在O中出現,如果出現則返回出現的位置。常規方法是遍歷a的每一個位置,然后從該位置開始和b進行匹配,但是這種方法的復雜度是O(nm)。kmp算法通過一個O(m)的預處理,使匹配的復雜度降為O(n+m)。

 

kmp算法思想

 

我們首先用一個圖來描述kmp算法的思想。在字符串O中尋找f,當匹配到位置i時兩個字符串不相等,這時我們需要將字符串f向前移動。常規方法是每次向前移動一位,但是它沒有考慮前i-1位已經比較過這個事實,所以效率不高。事實上,如果我們提前計算某些信息,就有可能一次前移多位。假設我們根據已經獲得的信息知道可以前移k位,我們分析移位前后的f有什么特點。我們可以得到如下的結論:

 

 

 

  • A段字符串是f的一個前綴。
  • B段字符串是f的一個后綴。
  • A段字符串和B段字符串相等。

 

 

 

所以前移k位之后,可以繼續比較位置i的前提是f的前i-1個位置滿足:長度為i-k-1的前綴A和后綴B相同。只有這樣,我們才可以前移k位后從新的位置繼續比較。

 


 

 

 

所以kmp算法的核心即是計算字符串f每一個位置之前的字符串的前綴和后綴公共部分的最大長度(不包括字符串本身,否則最大長度始終是字符串本身)。獲得f每一個位置的最大公共長度之后,就可以利用該最大公共長度快速和字符串O比較。當每次比較到兩個字符串的字符不同時,我們就可以根據最大公共長度將字符串f向前移動(已匹配長度-最大公共長度)位,接著繼續比較下一個位置。事實上,字符串f的前移只是概念上的前移,只要我們在比較的時候從最大公共長度之后比較f和O即可達到字符串f前移的目的。


next數組計算

 

 

 

理解了kmp算法的基本原理,下一步就是要獲得字符串f每一個位置的最大公共長度。這個最大公共長度在算法導論里面被記為next數組。在這里要注意一點,next數組表示的是長度,下標從1開始;但是在遍歷原字符串時,下標還是從0開始。假設我們現在已經求得next[1]、next[2]、……next[i],分別表示長度為1到i的字符串的前綴和后綴最大公共長度,現在要求next[i+1]。由上圖我們可以看到,如果位置i和位置next[i]處的兩個字符相同(下標從零開始),則next[i+1]等于next[i]加1。如果兩個位置的字符不相同,我們可以將長度為next[i]的字符串繼續分割,獲得其最大公共長度next[next[i]],然后再和位置i的字符比較。這是因為長度為next[i]前綴和后綴都可以分割成上部的構造,如果位置next[next[i]]和位置i的字符相同,則next[i+1]就等于next[next[i]]加1。如果不相等,就可以繼續分割長度為next[next[i]]的字符串,直到字符串長度為0為止。由此我們可以寫出求next數組的代碼(Java版):

 1 public int[] getNext(String b) 2 { 3     int len=b.length(); 4     int j=0; 5          6     int next[]=new int[len+1];//next表示長度為i的字符串前綴和后綴的最長公共部分,從1開始 7     next[0]=next[1]=0; 8          9     for(int i=1;i<len;i++)//i表示字符串的下標,從0開始10     {//j在每次循環開始都表示next[i]的值,同時也表示需要比較的下一個位置11         while(j>0&&b.charAt(i)!=b.charAt(j))j=next[j];12         if(b.charAt(i)==b.charAt(j))j++;13         next[i+1]=j;14     }15         16     return next;17 }

 

上述代碼需要注意的問題是,我們求取的next數組表示長度為1到m的字符串f前綴的最大公共長度,所以需要多分配一個空間。而在遍歷字符串f的時候,還是從下標0開始(位置0和1的next值為0,所以放在循環外面),到m-1為止。代碼的結構和上面的講解一致,都是利用前面的next值去求下一個next值。

字符串匹配

計算完成next數組之后,我們就可以利用next數組在字符串O中尋找字符串f的出現位置。匹配的代碼和求next數組的代碼非常相似,因為匹配的過程和求next數組的過程其實是一樣的。假設現在字符串f的前i個位置都和從某個位置開始的字符串O匹配,現在比較第i+1個位置。如果第i+1個位置相同,接著比較第i+2個位置;如果第i+1個位置不同,則出現不匹配,我們依舊要將長度為i的字符串分割,獲得其最大公共長度next[i],然后從next[i]繼續比較兩個字符串。這個過程和求next數組一致,所以可以匹配代碼如下(java版):

 1 public void search(String original, String find, int next[]) { 2     int j = 0; 3     for (int i = 0; i < original.length(); i++) { 4         while (j > 0 && original.charAt(i) != find.charAt(j)) 5             j = next[j]; 6         if (original.charAt(i) == find.charAt(j)) 7             j++; 8         if (j == find.length()) { 9             System.out.println("find at position " + (i - j));10             System.out.println(original.subSequence(i - j + 1, i + 1));11             j = next[j];12         }13     }14 }

 

上述代碼需要注意的一點是,每次我們得到一個匹配之后都要對j重新賦值。

 

復雜度

 

kmp算法的復雜度是O(n+m),可以采用均攤分析來解答,具體可參考算法導論。

 

參考資料

 

1.     kmp算法小結

 

2.     kmp算法詳解

 

3.     kmp算法

 

4.     kmp算法的理解與實現

 

 

 

開源實現

如果大家想實際用該算法,給大家提供一個實例:java記事本

 

 

PS:

 

最后再給大家補幾個圖,希望有助于大家理解。

 

 

科赫曲線

 

 

自身結構重復展開

 

隱藏目錄
本站僅提供存儲服務,所有內容均由用戶發布,如發現有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
子字符串查找(上):從暴力算法到KMP
Go 數據結構和算法篇(十二):字符串匹配之 KMP 算法
字符串硬核講解
字符串處理相關算法
「算法」面試題:KMP 字符串匹配算法
用動態規劃思想簡化理解KMP算法
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯系客服!

聯系客服

主站蜘蛛池模板: 饶河县| 平果县| 根河市| 滦南县| 长顺县| 龙海市| 淳安县| 辽中县| 隆尧县| 稷山县| 宝兴县| 仙居县| 镇安县| 洛浦县| 和硕县| 宜川县| 大田县| 鸡泽县| 偃师市| 东阳市| 盐亭县| 来凤县| 陕西省| 平谷区| 马鞍山市| 林芝县| 莆田市| 麻城市| 南部县| 灵丘县| 乌拉特前旗| 柳州市| 阿克苏市| 如皋市| 五寨县| 临安市| 古交市| 华亭县| 泰来县| 岗巴县| 台北县|