主要思路
找出模式串的next数字,然后将主串和模式串比较,匹配时则继续,不匹配时则模式串根据next数组回溯,直到模式串完全匹配,此时主串指针的位置减去模式串指针的位置即为主串中模式串的起始位置;模式串没有完全匹配则表示主串中不存在该模式串。
求模式串的next数组
例子:
A | B | A | B | A |
---|---|---|---|---|
-1 | 0 | 0 | 1 | 2 |
主要逻辑是P[ 0 ~ k-1 ] = P[ j-k ~ j-1 ]。因为k=0时,k-1<0表示k左边没有可以回溯的,所以next[0]总是等于-1。
private int[] getNext(char[] keys) {
int[] next = new int[keys.length];
next[0] = -1;
int i = -1, j = 0;
while (j < keys.length - 1) {
// 当i=-1时依然表示没有可以再回溯的东西,所以直接将++j回溯的位置置为0。
// keys[i]=keys[j]表示 0~i 和 j-i~j 相匹配,所以++j不匹配时的回溯位置自然就是++i。
if (i == -1 || keys[i] == keys[j]) {
next[++j] = ++i;
} else {
// keys[i]!=keys[j]时表示模式串需要回溯,因为之前已经求出了回溯的位置,
// 所以直接通过先前求出的next数组获取回溯的位置
i = next[i];
}
}
return next;
}
求主串和模式串匹配的位置
主要逻辑是将主串和模式串从头开始一一比较,如果相等则继续比较下一位字符,若不相等则根据next数组将模式串回溯,直到模式串全部匹配成功,则表示匹配成功。
private int getKeys(char[] str, char[] keys) {
int i = 0, j = 0;
// 首先获取模式串的next数组
int[] next = getNext(keys);
// 主串和模式串从头开始一一比较
while (i < str.length && j < keys.length) {
// 主串与模式串相等或者模式串回溯到-1时直接比较下一位
if (j == -1 || str[i] == keys[j]) {
i++;
j++;
} else {
// 不匹配时回溯模式串
j = next[j];
}
}
// 模式串全部匹配成功
if (j == keys.length) {
// 返回主串中模式串的位置
return i - j;
}
return -1;
}