以下内容是我看尚学堂视频所做的学习笔记
适合曾经学过KMP算法,理解大概原理但是写不出或者不太理解代码的同学,不适合KMP小白。
1. 理论回顾
2. java代码实现
2.1 求解next数组
假设已经知道next[y]
的取值为len
,求next[y+1]
的值。
- 若
P[len] == P[y]
,则next[y+1] = len + 1 = next[y] + 1
;
- 若
P[len]≠P[y]
,则循环地执行len = next[len]
,直到len==-1
或者满足P[len] == P[y]
为止。当t==0
时,next[j+1]=1
。
由此可得以下代码:
//计算next数组
public static int[] getNext(String subStr){
//1. 定义一个next数组
int[] next = new int[subStr.length()];
//2. 设置next数组的第一个元素值为-1
next[0] = -1;
//3. 定义两个变量,y表示模式串的索引值,len表示当索引为y时,最长公共前后缀的长度
int y = 0, len = -1;
//4. 定义一个循环,用于计算next数组
while(y < subStr.length()-1){
//5. 处理len和y指向模式串中的字符相等的情况
if(len == -1 || subStr.charAt(len) == subStr.charAt(y)){
len++;
y++;
next[y] = len;
}else{
//6. 处理len和y指向模式串中的字符不相等的情况
len = next[len];
}
}
//7. 返回
return next;
}
2.2 完整代码
import java.util.Arrays;
public class Test {
public static void main(String []args) {
//主串
String destStr = "BABABACABABCABAABD";
//模式串
String subStr = "ABABCABAAB";
//测试next数组
int[] next = getNext(subStr);
System.out.println(Arrays.toString(next));
//测试kmp算法
int index = kmp(destStr, subStr);
System.out.println(index);
}
//计算next数组
public static int[] getNext(String subStr){
//1. 定义一个next数组
int[] next = new int[subStr.length()];
//2. 设置next数组的第一个元素值为-1
next[0] = -1;
//3. 定义两个变量,y表示模式串的索引值,len表示当索引为y时,最长公共前后缀的长度
int y = 0, len = -1;
//4. 定义一个循环,用于计算next数组
while(y < subStr.length()-1){
//5. 处理len和y指向模式串中的字符相等的情况
if(len == -1 || subStr.charAt(len) == subStr.charAt(y)){
len++;
y++;
next[y] = len;
}else{
//6. 处理len和y指向模式串中的字符不相等的情况
len = next[len];
}
}
//7. 返回
return next;
}
//实现KMP算法
public static int kmp(String destStr, String subStr){
//0. 计算next数组
int[] next = getNext(subStr);
//1. 定义两个变量,分别指向主串和模式串中的第一个字符
int x = 0, y = 0;
//2. 定义一个循环,用于实现字符串的匹配操作
while(x < destStr.length() && y < subStr.length()){
if(y == -1 || destStr.charAt(x) == subStr.charAt(y)){
//3. 如果相等,则继续比较后续字符
x++;
y++;
}else{
//4. 如果不等,则主串指针不动,模式串指针回溯
y = next[y];
}
}
//5. 如果模式串遍历结束,则匹配成功,否则失败
if(y == subStr.length()) return x - y;
else return -1;
}
}
执行结果:
[-1, 0, 0, 1, 2, 0, 1, 2, 3, 1]
7