字串匹配演算法之KMP演算法詳情
阿新 • • 發佈:2018-11-27
package demo; /* 字串匹配演算法 */ public class StringKMP { //找出從第一個字元開始 子串T在主串S的第一個位置 如果沒有則返回-1 public static int index(String S, String T) { int tag = 0; int i = 0; int j = 0; char[] s = S.toCharArray(); char[] t = T.toCharArray(); while (i < s.length && j < t.length) { tag++; if (s[i] == t[j]) { i++; j++; } else { i = i - j + 1; j = 0; //一旦不等,j就從0開始 } } System.out.println("迴圈了" + tag + "次"); if (j == t.length) { return i - j; } else { return -1; } } /** * 使用kmp演算法的情況下 * kmp原理,就是 每次匹配的時候,如果t[j]和s[i]不相等,j不是從零開始,而是從k開始,k的特點是 t的0到k-1個位置字元和j-1 到 j-k-1個字元相等 * 比如說 * ababd在和ababfababde 匹配的時候 * ababfababde * ababd * 在j=4的時候不匹配時,也就是t[4]=d 不匹配的時候,j的下一個值不是0 ,而是2, 即t[2]=a ,而且此時i指標也不需要動 * 此時比對場景為 * ababfababde * ababd 此時 在t[2]仍然不匹配 j的下一個值是0 * <p> * ababfababde 此時t[0]時候 仍然不匹配 ,則i要向前移動1位 * ababd * <p> * <p> * ababfababde 此時匹配成功返回i * ababd * <p> * <p> * <p> * 因此 這裡會發現,求j的下一個值 next[j] 等同於是在求 第j個字元前面的,最大相同字首和和字尾的長度 * 比如說 ababf f前面的最大相同字首和字尾為ab 和ab 長度為2 因此next[4]=2 * <p> * t=2的時候 也就是aba 第三個a前面的ab ,最大相同字首和字尾長度為0 因此next[2]=0 * <p> * 最大字首: 包含第一個字元,不包含最後一個字元 * 最大字尾:包含最後一個字元,不包含第一個字元 * <p> * 最大相同前後綴,即字首和字尾相同的部分 最大長度的 * * @param */ public static int KMP(String S, String T) { int tag = 0; int[] next = next(T); int i = 0; int j = 0; next[0] = -1; char[] s = S.toCharArray(); char[] t = T.toCharArray(); while (i < s.length && j < t.length) { tag++; if (j == -1 || s[i] == t[j]) { i++; j++; } else { j = next[j]; } } System.out.println("迴圈了" + tag + "次"); if (j == t.length) { return i - j; } else { return -1; } } public static int[] next(String T) { char[] t = T.toCharArray(); int[] next = new int[t.length]; next[0] = -1;//-1表示不存在 int i = 0; int j = 1; while (j < t.length) { if (i == -1 || t[i] == t[j]) { i++; next[j] = i; j++; } else { i = next[i]; } } for (int i1 : next) { System.out.print(i1); } System.out.println(); return next; } public static void main(String[] args) { System.out.println(index("abcdefabcdefabcdefabcdefabcabcabcabcdeh", "abcdeh")); //迴圈了68次 System.out.println(index("abc", "bc")); //迴圈了3次 next("abcabc");//-100123 System.out.println(KMP("abc", "bc")); //迴圈了4次 System.out.println(KMP("abcdefabcdefabcdefabcdefabcabcabcabcdeh", "abcdeh"));//迴圈了50次 System.out.println(KMP("abcdeiopsfsfasdaffabcdefabcdefabcdefabcabcabcabcdehabcdes", "abcdeh"));//迴圈了74次 } }