现在回过头来看觉得没什么难度,但是刚开始看的时候看那些直接套用公式的代码,完全没法理解(专家盲点(Curse of knowledge))(感谢这个博主七年前的帖子)把next[]数组讲明白,但是发现自己也很难给别人讲明白 。先记录下自己思考的笔记,看看能不能渡有缘人
但是,对比起Sunday等其他搜索算法,真的觉得KMP几个巧妙的步骤真的复杂而没有必要。。建议直接sunday
KMP
BBCXABCDABXBCDABCDABDE
ABCDABD
X处失败时,返回上一位,前缀后缀最长公共元素长度AB=2,即从后缀AB处再开始对比,直接从开始X与C对比
模式串 | A | B | C | D | A | B | D |
---|---|---|---|---|---|---|---|
前缀后缀最长公共元素 | 0 | 0 | 0 | 0 | 1 | 2 | 0 |
next[] | -1 | 0 | 0 | 0 | 0 | 1 | 2 |
next[] 便于查找时判断子串从前往后是否有重复项
KMP的关键也就是建next[]数组:
往后遍历
先判断j是否与第一个元素相同
标记&next[j+1]=1
判断第二个元素...
private void getNext(String p, int next[]) {
int len = p.length();
int i = 0;
int j = -1;
next[0] = -1;//这个默认的,
while (i < len - 1) {
if (j == -1 || p.charAt(i) == p.charAt(j)) {
i++;
j++;
next[i] = j;
} else
j = next[j];//restart from head
}
}
例子
母串H [i]
子串N [j]
回退next[]
i,j 从头开始比较,当H[i]!=N[j],如例子中i=10,j=6
向右移动子串j-next[j]=4
BBCXABCDABXBCDABCDABDE
ABCDABD
并且继续从i处开始比较(j=next[j]=2),...右移...☞匹配
public int strStr(String haystack, String needle) {
if (needle.length() == 0)
return 0;
int i = 0;
int j = 0;
int[] next = new int[needle.length()];
getNext(needle, next);
while (i < haystack.length() && j < needle.length()) {
if (j == -1 || haystack.charAt(i) == needle.charAt(j)) {
i++;
j++;
} else {
j = next[j]; // j回到指定位置
}
if (j == needle.length())
return i - j;
}
return -1;
}