kmp算法代码实现主要分成两部分,一个是getNext()计算next数组, 另外是strStr()字符串匹配过程。
next数组
next数组的作用:在发现字符匹配失败时,可以通过next知道模拟串应该回溯的位置
next数组的含义:模拟串在当前位置与其前面的字符构成的字符串的最长公共前后缀
注:
- 前缀:从第一个字符开始(必须),到最后一个字符之前的所有字符构成的连续子串为前缀
- 后缀:从第一个字符之外的字符开始,以最后一个字符结尾的所有字符构成的连续字串为后缀
next数组为什么能起到这个作用:因为找到了最长相等的前缀和后缀,匹配失败的是后缀子串的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了
求next数组
// i:后缀末尾
// j:前缀末尾(同时代表之前的子串最长相等前后缀长度)
// 过程当前指向i、j相等时,当前的子串最长相等前后缀+1;否则j回退,直到i、j指向位置相等,或者j=0
// 为什么要回退:因为要重新找相等前后缀
public void getNext(String needle){
int j = 0;
for(int i = 1;i < needle.length(); i++){
while(j>0 && needle.charAt(i) != needle.charAt(i)){
j = next[j-1];
}
if(needle.charAt(i) == needle.charAt(j)) j++;
next[i] = j;
}
}
字符串匹配过程
这个就比较简单了,主要是遍历主串的时候同时遍历模拟串,如果主串和模拟串不匹配,则模拟串通过next数组回退,直到遍历完模板串或者遍历完主串未遍历完模板串
public int strStr(String haystack, String needle) {
next = new int[needle.length()];
getNext(needle);
int hayLen = haystack.length();
int j = 0;
for(int i = 0; i < hayLen; i++){
if(haystack.charAt(i) == needle.charAt(j)){
j++;
}
if(j == needle.length()){
return i - needle.length() + 1;
}
while(j>0 && haystack.charAt(i) != needle.charAt(j)){
j = next[j - 1];
}
}
return -1;
}