package org.nix.learn.use;
/**
* kmp算法求解過程
* 1.求出部分匹配值(next)
* 2.給出三個指針:
* 1.記錄字串的匹配指針(用來指定匹配到了哪兒了,當未完全匹配時用於計算位移值)
* 2.記錄母串的開始匹配位子(用於如果未匹配而計算下一次指針應該在哪兒)
* 3.記錄母串指針的當前值(跟隨着匹配狀態移動)
* 3.返回匹配的結果
* @author zhangpei
* @version 1.0
* @date 2018/9/19
*/
public class KMP {
public static void main(String[] args) {
String test = "BBC ABCDAB ABCD ABCDABD E";
String str = "ABCDABD";
// System.out.println(getNext(preStr(str), suffixStr(str)));
// for (String s : suffixStr(str)) {
// System.out.print(s + " ");
// }
// System.out.println();
// for (int s : getNexts(str)) {
// System.out.print(s + " ");
// }
// System.out.println();
System.out.println(kmp(test,str));
}
/**
* 調用kmp算法獲取到 model字符串在target字符串中的位子
* @param target 模板字符串
* @param model 需要查找的字符串
* @return model的首字母在target的位子
*/
public static int kmp(String target,String model){
int lenTar = target.length();
int lenModel = model.length();
// 得到next數組
int[] next = getNexts(model);
// 指向目標字符串
int tarPoin = 0;
// targetPoin的開始值
int tempTarPoin = tarPoin;
// 指向已經匹配的字符
int modelPoin = 0;
for (int i = 0; i < lenTar; i++) {
if (tarPoin >= lenTar){
return -2;
}
// 匹配完整,返回首個字符匹配的位子
if (modelPoin == lenModel){
return tempTarPoin;
}
// 當不能匹配時
if (target.charAt(tarPoin)!=model.charAt(modelPoin)){
// 查詢上一個匹配的值的部分匹配值是多少
int n = next[modelPoin];
int move = modelPoin-n;
// 下一次指針座標
tarPoin = tempTarPoin + move+1;
// 這一次的記錄座標
tempTarPoin = tarPoin;
modelPoin = 0;
}else {
tarPoin++;
modelPoin++;
}
}
return -1;
}
/**
* 求出前綴
* 前綴:除了最後一個字符外的所有其他字符的組合
*
* @param str 目標字符串
* @return 前綴集合
*/
public static String[] preStr(String str) {
// 去除最後個字符
String air = str.substring(0, str.length() - 1);
int airLen = air.length();
String[] returnStr = new String[airLen];
char[] temps = air.toCharArray();
for (int i = 0; i < airLen; i++) {
if (i == 0) {
returnStr[i] = String.valueOf(temps[i]);
} else {
returnStr[i] = returnStr[i - 1] + String.valueOf(temps[i]);
}
}
return returnStr;
}
/**
* 求出後綴
* 除了第一個字符外的字符的全部組合
*
* @param str 目標字符串
* @return 後綴集合
*/
public static String[] suffixStr(String str) {
// 去除第一個字符
String air = str.substring(1, str.length());
int airLen = air.length();
String[] reult = new String[airLen];
for (int i = 0; i < airLen; i++) {
reult[i] = air.substring(i, airLen);
}
return reult;
}
/**
* "部分匹配值"就是"前綴"和"後綴"的最長的共有元素的長度
*
* @param pre 前綴
* @param suffix 後綴
* @return 最長的共有元素的長度
*/
public static int getNext(String[] pre, String[] suffix) {
int len = suffix.length;
int startSuffix = len;
int temp = 0;
for (int i = 0; i < len; i++) {
if (pre[i].equals(suffix[--startSuffix])) {
int preLen = pre[i].length();
if (temp < preLen) {
temp = preLen;
}
}
}
return temp;
}
public static int[] getNexts(String str){
int len = str.length();
int[] next = new int[len];
for (int i = 0; i <len ; i++) {
String son = str.substring(0,i+1);
next[i] = getNext(preStr(son),suffixStr(son));
}
return next;
}
}
原理後面再說= =,只知道如何算,還不知道這個理論如何出來的
參考:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
github: https://github.com/zhangpeibisha