···
package newcoder;
public class KMP {
/**
* 判斷str1中是否有str2,如果有返回在str1中的開始下標
*
* @param str1
* @param str2
* @return
*/
public int getIndex(String str1, String str2) {
char[] c1 = str1.toCharArray();
char[] c2 = str2.toCharArray();
int[] next = getNext(c2);
int i1 = 0, i2 = 0;
while (i1 < str1.length() && i2 < str2.length()) {
if (c1[i1] == c2[i2]) {
i1++;
i2++;
} else if (next[i2] == -1) {
//第一個位置就讓i1後移
i1++;
} else {
i2 = next[i2];
}
}
return i2 == str2.length() ? i1 - i2 : -1;
}
/**
* 得到c2的每個元素的前綴和後綴相等的個數
*
* @param c2
* @return
*/
private int[] getNext(char[] c2) {
int next[] = new int[c2.length];
next[0] = -1;
next[1] = 0;
int i = 2, cn = 0;//cn當前前綴的長度
while (i < c2.length) {
//當前前綴位置的元素等於i-1位置的元素
//位置前綴就加一,cn加一
if (c2[cn] == c2[i - 1]) {
next[i] = cn + 1;
i++;
cn++;
} else {
//在cn前面繼續劃分找到和i-1位置匹配的元素,沒有就爲0
if (cn > 0) {
cn = next[cn];
} else {
next[i++] = 0;
}
}
}
return next;
}
/**
* 將給出的字符串變成含有兩個源字符串的最短字符串
*
* @param str
* @return
*/
public String getShort(String str) {
char[] chars = str.toCharArray();
//計算最長前綴,並且多算一個 然後字符串長度減去最後位置上的前綴長度,就是在末尾添加的字符個數
int[] next = new int[chars.length + 1];
next[0] = -1;
next[1] = 0;
int i = 2;
int cn = 0;
while (i < chars.length + 1) {
if (chars[i - 1] == chars[cn]) {
next[i++] = ++cn;
} else if (cn == 0) {
i++;
} else {
cn = next[cn];
}
}
i = next[chars.length];
StringBuilder sb = new StringBuilder(str);
while (i < chars.length) {
sb.append(chars[i++]);
}
return sb.toString();
}
public static void main(String[] args) {
KMP kmp = new KMP();
int n[] = kmp.getNext(new char[]{'a', 'b', 'a', 'b', 'c', 'a', 'b', 'c'});
int n1[] = kmp.getNext(new char[]{'a', 'a', 'a', 'a', 'a', 'a', 'b', 'c'});
String s1 = "acbababa", s2 = "ab";
System.out.println(kmp.getIndex(s1, s2));
for (int i : n) {
System.out.println(i);
}
System.out.println(kmp.getShort(s1));
}
}