日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

KMP算法--深入浅出

發布時間:2025/3/21 编程问答 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 KMP算法--深入浅出 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說明:

在網上查了各種資料,終于對KMP算法有了透徹的了解,都說KMP特簡單,我咋沒有察覺呢?難道是智商不在線?或許都是騙紙?

還是進入正題吧,整理整理大佬的blog

KMP算法簡介:

KMP算法是一種改進的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同時發現。KMP算法的關鍵是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是實現一個next()函數,函數本身包含了模式串的局部匹配信息。時間復雜度O(m+n)。

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

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

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

所以kmp算法的核心即是計算字符串F每一個位置之前的字符串的前綴和后綴公共部分的最大長度(不包括字符串本身,否則最大長度始終是字符串本身)。

獲得F每一個位置的最大公共長度之后,就可以利用該最大公共長度快速和字符串S比較。當每次比較到兩個字符串的字符不同時,我們就可以根據最大公共長度將字符串F向前移動(已匹配長度-最大公共長度)位,接著繼續比較下一個位置。事實上,字符串F的前移只是概念上的前移,只要我們在比較的時候從最大公共長度之后比較F和S即可達到字符串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數組的代碼:

void cal_next(char *str, int *next, int len) {next[0] = -1;//next[0]初始化為-1,-1表示不存在相同的最大前綴和最大后綴int k = -1;//k初始化為-1for (int q = 1; q <= len-1; q++){while (k > -1 && str[k + 1] != str[q])//如果下一個不同,那么k就變成next[k],注意next[k]是小于k的,無論k取任何值。 {k = next[k];//往前回溯 }if (str[k + 1] == str[q])//如果相同,k++ {k = k + 1;}next[q] = k;//這個是把算的k的值(就是相同的最大前綴和最大后綴長)賦給next[q] } }

?

?

?

四:字符串匹配

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

int KMP(char *str, int slen, char *ptr, int plen) {int *next = new int[plen];cal_next(ptr, next, plen);//計算next數組int k = -1;for (int i = 0; i < slen; i++){while (k >-1&& ptr[k + 1] != str[i])//ptr和str不匹配,且k>-1(表示ptr和str有部分匹配)k = next[k];//往前回溯if (ptr[k + 1] == str[i])k = k + 1;if (k == plen-1)//說明k移動到ptr的最末端 {//cout << "在位置" << i-plen+1<< endl;//k = -1;//重新初始化,尋找下一個//i = i - plen + 1;//i定位到該位置,外層for循環i++可以繼續找下一個(這里默認存在兩個匹配字符串可以部分重疊),感謝評論中同學指出錯誤。return i-plen+1;//返回相應的位置 }}return -1; }

?

轉載于:https://www.cnblogs.com/GHzz/p/9147073.html

總結

以上是生活随笔為你收集整理的KMP算法--深入浅出的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。