如果想了解KMP算法,我还写了 一篇 篇幅更大的KMP算法,里面更加详细的推理的KMP算法的理论过程。
【字符串常用算法】——KMP算法(你别闲烦 超详细,给你解释明白)
function strStr(haystack: string, needle: string): number {
//获取长度
const haystackLen = haystack.length,
needleLen = needle.length;
// 如果长度相等并且值相等,则直接返回 0,否则返回-1
if (haystackLen === needleLen) {
return haystack === needle ? 0 : -1;
}
// 根据 模式串的长度创建next数组
const nextList: number[] = Array(needleLen).fill(0);
// i 和 j 是模式串的快慢指针,i为快指针,j为慢指针
// i 用来表示最大后缀,j为最大前缀
for (let i = 1, j = 0; i < needleLen; i++) {
// 当模式串的的快慢指针值不相等时,
// 如果前缀与后缀不相等,则将前缀回退到前一个字符的next值
// 因为上一个字符的next值已经算出来了,没有必要再对比串更少的字符了
while (j > 0 && needle[i] !== needle[j]) {
j = nextList[j - 1];
}
//如果两个字符相等,则前缀可以向后移动一个字符
if (needle[i] === needle[j]) {
j++;
}
//赋值next数组
nextList[i] = j;
}
//其实这步和之前很像,几乎是一样的逻辑
for (let i = 0, j = 0; i < haystackLen; i++) {
// 如果前缀与后缀不相等,则将前缀回退到前一个字符的next值
//此时 j 指向模式串的索引,表示如果该字符匹配失败,则字符串和模式串的哪个字符比较
while (j > 0 && haystack[i] !== needle[j]) {
j = nextList[j - 1];
}
//前缀与后缀相等,则匹配模式串的下一位
if (haystack[i] === needle[j]) {
j++;
}
//完成匹配成功
if (j === needleLen) {
//返回其开头索引
return i - needleLen + 1;
}
}
return -1;
}