一、什么是 KMP 算法
KMP 算法是一種改進的字符串匹配算法,用於判斷一個字符串是否是另一個字符串的子串
二、KMP 算法的時間復雜度
O(m+n)
三、Next 數組 - KMP 算法的核心
KMP算法的核心是利用匹配失敗后的信息,盡量減少模式串與主串的匹配次數以達到快速匹配的目的。具體實現就是通過一個 next() 實現
1、next 數組:
長度與字符串長度一致,每個位置存儲對應字符的最長匹配長度
2、next 數組通過遍歷子字符串中"前綴"和"后綴"的最長的共有元素的長度來獲得
例如 ABCDABD,得到的 next 數組為 [0,0,0,0,1,2,0]
簡單地觀察一下就會發現,該算法會進行最少 21 次的字符串判斷,這還是在不考慮字符串匹配的時間消耗,光此一項的時間復雜度就是
O(n) = (n(n - 1)) /2 = n² / 2 + n / 2 = n²
在加上匹配字符串,就是m + n²顯然大於KMP算法的時間復雜度m + n
3、next數組通過加入回溯法,在遍歷子字符串時,判斷逐步判斷字符是否相同
function get_next(s) { var i = 1; var j = 0; var next = [0]; while (i < s.length) { if (j == 0 || s.charAt(i - 1) == s.charAt(j - 1)) { i++; j++; next.push(j); } else { j = next[j - 1]; } } return next; }
例如:
j=0, i=1, (j=0), next=[0,1]; j=1, i=2, (A!=B), j=next[0]; j=0, i=2, (j=0), next=[0,1,1]; j=1, i=3, (A!=C), j=next[0]; j=0, i=3, (j=0), next=[0,1,1,1]; j=1, i=4, (A!=D), j=next[0]; j=0, i=4, (j=0), next=[0,1,1,1,1]; j=1, i=5, (A=A), next=[0,1,1,1,1,2]; j=2, i=6, (B=B), next=[0,1,1,1,1,2,3];
總共運行9次就獲得了next數組,算法時間復雜度是O(n) = n
4、對於兩個next數組的用法也有區別
//1.阮 //i值即移動位數:移動位數 = 已匹配的字符數 - 對應的部分匹配值 function kmp(s1, s2) { var next = getNext(s2); var j = 0; for (var i = 0; i < s1.length;) { for (; j < s2.length; j++) { if (s1.charAt(i + j) != s2.charAt(j)) { i += j > 0 ? (j - next[j - 1]) : 1; j = next[j > 0 ? j - 1 : 0]; break; } else if (j == s2.length - 1) { return i; } } } return -1; } //2.程 function kmp2(s1, s2) { var j = 0; var next = get_next(s2); for (var i = 0; i < s1.length;) { for (; j < s2.length; j++) { if (s1.charAt(i) != s2.charAt(j)) { j == 0 ? i++ : true; j = next[j > 0 ? j - 1 : 0]; break; } else if (j == s2.length - 1) { return i - j; } i++; } } return -1; } //3.也正是由於i值的大小隨着j值的大小進行改變, // 使得被查找字符串僅被遍歷一次即可得到解。 // 故時間復雜度為m // 加上獲得next數組的時間復雜度就是kmp算法的總時間復雜度m+n;