來去學習之---KMP演算法--next計算過程
一、概述
KMP演算法是一種字串匹配演算法,比如現有字串
T:ABCDABCDABCDCABCDABCDE,
P:ABCDABCDE
P字串對應的next值:[0,0,0,0,1,2,3,4,0]
二、匹配過程
判斷T字串是否包含P字串?下面看一下KMP的比較過程:
三、next陣列計算過程
先了解一下字串的前後綴(具體來說是真前後綴即 字首不包含最後一個字元;字尾不包含第一個字元)
字串 |
真字首 |
真字尾 |
真前、字尾中相 同的字串 |
真前、字尾中 最大相同串 |
真前、字尾中最 大相同串字元數 |
abc |
a,ab |
bc,c |
無 |
無 |
0 |
aaa |
a,aa |
aa,a |
a,aa |
aa |
2 |
aba |
a,ab |
ba,a |
a |
a |
1 |
abab |
a,ab,aba |
bab,ab,b |
ab |
ab |
2 |
ababab |
a,ab,aba,abab,ababa |
babab,abab,bab,ab,b |
ab,abab |
abab |
4 |
那“ABCDABCDE”字串的最大真前後綴的計算過程如下:
子串 |
真字首字串 |
真字尾字串 |
真前、字尾中最 大相同串字元 |
真前、字尾中最 大相同串字元數 |
A |
無 |
無 |
無 |
0 |
AB |
A |
B |
無 |
0 |
ABC |
AB、A |
BC、C |
無 |
0 |
ABCD |
ABC、AB、A |
BCD、CD、D |
無 |
0 |
ABCDA |
ABCD、ABC、AB、A |
BCDA、CDA、DA、A |
A=A |
1 |
ABCDAB |
ABCDA、ABCD、ABC、AB、A |
BCDAB、CDAB、DAB、AB、B |
AB=AB |
2 |
ABCDABC |
ABCDAB、ABCDA、ABCD、 ABC、AB、A |
BCDABC、CDABC、DABC、 ABC、BC、C |
ABC=ABC |
3 |
ABCDABCD |
ABCDABC、ABCDAB、ABCDA、 ABCD、ABC、AB、A |
BCDABCD、CDABCD、DABCD、 ABCD、BCD、CD、D |
ABCD=ABCD |
4 |
ABCDABCDE |
ABCDABCD、ABCDABC、ABCDAB、 ABCDA、ABCD、ABC、AB、A |
BCDABCDE、CDABCDE、DABCDE、 ABCDE、BCDE、CDE、DE、E |
無 |
0 |
由上表得出最大真前後綴的結果為:{0,0,0,0,1,2,3,4,0}
接下來需要把這最大真前後綴值轉換為next值
索引 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
字串 |
A |
B |
C |
D |
A |
B |
C |
D |
E |
最大真前後綴數 |
0 |
0 |
0 |
0 |
1 |
2 |
3 |
4 |
0 |
Next |
-1 |
0 |
0 |
0 |
0 |
1 |
2 |
3 |
4 |
通過上面的表格可以發現就是把最大真前後綴的值整體向後以後一位,所以next值為:{-1,0,0,0,0,1,2,3,4},計算出這個next陣列之後,接下來在匹配的過程中就可以使用了。
注意:有的人感覺使用最大真前後綴也可以作為next值,這是可以作為的,只是在計算最大真前後綴的邏輯程式碼相對複雜一點點,並且在匹配使用的時候也會複雜一點點
四、實現程式碼
計算next值的程式碼
1 public static int[] computeNext(char[] chs) { 2 int i = 0; 3 int j = -1; 4 int[] next = new int[chs.length]; 5 next[i] = j; 6 while (i < chs.length - 1) { 7 if (j == -1 || chs[i] == chs[j]) { 8 i++; 9 j++; 10 next[i] = j; 11 } else { 12 j = next[j]; 13 } 14 } 15 return next; 16 }
計算最大真前後綴的程式碼:
1 public static int[] getPreSuffix(char[] cs) { 2 int j = 0; 3 int i = 1; 4 int len = cs.length; 5 int[] preSuffix = new int[len]; 6 preSuffix[1] = 0; 7 while (i < len) { 8 if (j == 0) { 9 if (cs[j] == cs[i]) { 10 preSuffix[i] = j + 1; 11 j++; 12 i++; 13 } else { 14 i++; 15 } 16 } else { 17 if (cs[j] == cs[i]) { 18 preSuffix[i] = j + 1; 19 j++; 20 i++; 21 } else { 22 j = preSuffix[j - 1]; 23 } 24 } 25 } 26 return preSuffix; 27 }
大家有什麼疑問、建議歡迎留言、討論!