public class KMP {
int[] next;
String pattern;
String target;
KMP(String target, String pattern) {
this.pattern = pattern;
this.target = target;
this.next = new int[this.pattern.length()];
}
public void createNext() {
int j = 0;
int i = 1;
this.next[0] = 0;
if (pattern.length() >= 2) // 至少有两个字符才能比较前缀和后缀
{
while (i < pattern.length())
{
// i 表示要计入的next数组的位置
while (i < pattern.length() && pattern.charAt(i) == pattern.charAt(j))
{
next[i] = j+1;
i++;
j++;
}
while (j > 0 && i < pattern.length() && pattern.charAt(i) != pattern.charAt(j))
{
j = next[j-1];
}
// 一直查找到j = 0
if (i < pattern.length() && pattern.charAt(i) != pattern.charAt(j))
{
next[i] = 0;
i++;
}
// 此时j > 0
else if (i < pattern.length() && pattern.charAt(i) == pattern.charAt(j))
{
next[i] = j+1;
i++;
j++;
}
}
}
}
public void showNext() {
for (int i = 0; i < this.next.length; i++)
System.out.print(this.next[i]);
}
public int findStr() {
int i = 0; // 标识主串的位置
int j = 0; // 表示模式串的位置
int ret = -1;
while (true)
{
int rem = i - j; // j表示已经匹配的字符个数
while (i < this.target.length() && j < this.pattern.length())
{
if (this.target.charAt(i) != this.pattern.charAt(j))
break;
i++;
j++;
}
if (this.target.length() - rem < this.pattern.length()) // target剩余的字符串长度短于pattern
break;
if (j == this.pattern.length()) // 已经找到pattern的起始位置
{
ret = rem;
break;
}
else if (j > 0) // 第二个字符开始出现不匹配,此时回退,回退后的新字符还是在主串的原位置进行比较
j = this.next[j-1];
else if (j == 0) // 第一个字符就不匹配
i++;
}
return ret;
}
public static void main(String[] args) {
KMP k = new KMP("abcaabaaab", "aabaaab");
k.createNext();
k.showNext();
System.out.println();
System.out.println(k.findStr());
}
}
其中,next数组的构造过程参见答案提供的思路