···
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));
}
}