一、什麼是KMP算法?
維基百科的解釋是:在計算機科學中,Knuth-Morris-Pratt字符串查找算法(簡稱爲KMP算法)可在一個主文本字符串S內查找一個詞W的出現位置。此算法通過運用對這個詞在不匹配時本身就包含足夠的信息來確定下一個匹配將在哪裏開始,從而避免重新檢查先前已經匹配過的字符。
二、字符串的前綴與後綴
前綴:字符串除了最後一個字符的全部頭部組合;
後綴:字符串處理第一個字符的全部頭部組合;例如
三、字符串部分匹配表
"部分匹配"的實質是,有時候,字符串頭部和尾部會有重複。比如,"ABCDAB"之中有兩個"AB",那麼它的"部分匹配值"就是2("AB"的長度)。搜索詞移動的時候,第一個"AB"向後移動4位(字符串長度-部分匹配值),就可以來到第二個"AB"的位置。所以我們需要找到一個字符串中每一個子串的匹配值,即找到字符串的部分匹配值表,這樣的話我們在下面匹配字符串的過程中就可以根據匹配表來進行跳躍了,而不必一個一個字符往後移,這就是關鍵所在。
四、KMP算法實現過程
簡單來說,KMP算法就是根據上面我們已經得到的部分匹配表來判斷:匹配過程中發現子串的某個字符與待匹配串不對應時,子串應該往後移幾位。
移動的位數 = 已經匹配成功的串的總長度 - 已經匹配成功的串的部分匹配值
有些繞,舉個栗子,假如我要判斷字符串"BBC ABCDAB ABCDABCDABDE"中是否含有串“ABCDABD”,我把前面這個長串叫做待匹配串,把“ABCDABD”叫做子串(有可能叫法不對但明白就行)。
匹配的過程爲:
將字符串"BBC ABCDAB ABCDABCDABDE"的第一個字符與搜索詞"ABCDABD"的第一個字符,進行比較。因爲B與A不匹配,所以搜索詞後移一位。直到有匹配的字符位置,如下:
圖中當匹配到D時發現不對應了,此時:
已經匹配成功的串爲:ABCDAB
已經匹配成功的串的總長度:6
已經匹配成功的串的部分匹配值 :2
移動的位數 = 6 - 2,直接將子串往後移動4位,繼續開始匹配
一樣的道理,此時已經匹配成功的串爲AB,移動的位數 = 2 - 0,往後移動2位繼續匹配
沒有匹配成功的串,往後移一位
已經匹配成功的串爲:ABCDAB,ABCDAB的部分匹配值爲2,移動的位數 = 6 - 2,往後移動4位
此時子串所有的字符都被匹配,搜索完成。
五、Java實現
public class KmpAlgo { //尋找待匹配串的部分匹配值,放在next數組中 static void getNext(String pattern,int[] next){ int j = 0; int k = -1; next[0] = -1; int len = pattern.length(); while(j < len-1){ if(k == -1 || pattern.charAt(j) == pattern.charAt(j)){ j++; k++; next[j] = k; }else{ k = next[k]; } } } static int kmp(String s,String pattern){ int i = 0; int j = 0; int slen = s.length(); int plen = pattern.length(); int[] next = new int[plen]; getNext(pattern,next); while(i < slen && j < plen){ if(s.charAt(i) == pattern.charAt(j)){ i++; j++; }else if(next[j] == -1){ i++; j = 0; }else{ j = next[j]; } if(j == plen){ return i-j; } } return -1; } /** *@param */ public static void main(String[] args){ String str = "ABCDABDEYGF"; String pat = "ABCDABD"; //KmpAlgo.kmp(str, pat); System.out.println(KmpAlgo.kmp(str, pat)); } }