返回
将“KMP”算法搬进JavaScript,点亮你的字符串搜索技术!
前端
2023-12-22 21:05:35
“KMP”算法的魅力
“KMP”算法,全称Knuth-Morris-Pratt算法,以它的三位创作者命名,是一种高效的字符串匹配算法,以它速度快、实现简单的特点闻名于世,经常被用来解决各种字符串搜索问题。
JavaScript版的“KMP”算法
要理解JavaScript版的“KMP”算法,首先我们需要了解它的两个核心概念:
- 前缀表(prefix table):前缀表是一个数组,用来存储每个子串的“最大公共前缀”。例如,对于字符串“ABCD”,前缀表的值为[0, 0, 0, 0],因为没有一个子串的前缀与后缀匹配。而对于字符串“ABAB”,前缀表的值为[0, 1, 1, 2],因为“AB”是“ABAB”的前缀和后缀。
- 匹配指针(matching pointer):匹配指针是一个整数,用来标记当前正在比较的字符在“needle”字符串中的位置。
算法步骤
有了这两个核心概念,我们就可以一步一步地了解JavaScript版的“KMP”算法了:
- 首先,我们创建一个前缀表。
- 然后,我们初始化匹配指针为0。
- 接下来,我们开始比较“haystack”字符串中的字符和“needle”字符串中的字符。
- 如果字符匹配,我们增加匹配指针并继续比较下一个字符。
- 如果字符不匹配,我们就将匹配指针重置为前缀表中该字符对应的值,然后继续比较下一个字符。
- 我们重复步骤3、4、5,直到“needle”字符串中的所有字符都与“haystack”字符串中的字符匹配,或者直到我们到达“haystack”字符串的末尾。
- 如果我们到达了“haystack”字符串的末尾,并且“needle”字符串中的所有字符都与“haystack”字符串中的字符匹配,那么我们就找到了“needle”字符串在“haystack”字符串中的位置。
- 如果我们到达了“haystack”字符串的末尾,但“needle”字符串中的所有字符都与“haystack”字符串中的字符匹配,那么我们就返回-1,表示“needle”字符串不在“haystack”字符串中。
实战应用
现在,让我们用JavaScript版的“KMP”算法来解决LeetCode上的一个字符串匹配难题:
题目:给定一个字符串“haystack”和一个字符串“needle”,在“haystack”字符串中找出“needle”字符串出现的第一个位置。如果不存在,则返回-1。
function kmp(haystack, needle) {
// 创建前缀表
const prefixTable = [];
prefixTable[0] = 0;
for (let i = 1; i < needle.length; i++) {
let j = prefixTable[i - 1];
while (j > 0 && needle[i] !== needle[j]) {
j = prefixTable[j - 1];
}
prefixTable[i] = j + (needle[i] === needle[j] ? 1 : 0);
}
// 匹配指针
let matchingPointer = 0;
// 开始比较
for (let i = 0; i < haystack.length; i++) {
while (matchingPointer > 0 && haystack[i] !== needle[matchingPointer]) {
matchingPointer = prefixTable[matchingPointer - 1];
}
if (haystack[i] === needle[matchingPointer]) {
matchingPointer++;
}
if (matchingPointer === needle.length) {
return i - needle.length + 1;
}
}
// 返回-1
return -1;
}
调用方法:
const haystack = "ABCDABAC";
const needle = "ABAC";
const result = kmp(haystack, needle);
console.log(result); // 输出:2
结语
通过JavaScript版的“KMP”算法,我们轻而易举地找到了“ABAC”字符串在“ABCDABAC”字符串中的位置。赶紧动手实现一下,让你的字符串搜索技术更上一层楼吧!