模式搜索是一种涉及搜索字符串、单词、图像等模式的算法。
我们使用某些算法来进行搜索过程。模式搜索的复杂性因算法而异。在数据库中执行搜索时它们非常有用。模式搜索算法对于在较大字符串的子字符串中查找模式非常有用。这个过程可以使用我们将在本文章中讨论的各种算法来完成。
朴素模式搜索是其他模式搜索算法中最简单的方法。它检查模式中主字符串的所有字符。该算法对于较小的文本很有帮助。它不需要任何预处理阶段。我们可以通过检查一次字符串来找到子字符串。它也不占用额外的空间来执行操作。
朴素模式搜索方法的时间复杂度为 O(m*n)。m 是模式的大小,n 是主字符串的大小。
// Naive Pattern 的 JS 程序
// 搜索算法
function search(pat, txt)
{
let M = pat.length;
let N = txt.length;
/* 逐个滑动 pat[] 的循环 */
for (let i = 0; i <= N - M; i++) {
let j = 0;
/* 对于当前索引 i,检查是否匹配模式 */
for (j = 0; j < M; j++) {
if (txt[i + j] != pat[j]) {
break;
}
}
if (j == M) {// if pat[0...M-1] = txt[i, i+1, ...i+M-1]
console.log("Pattern found at index",i);
}
}
}
let txt = "AABAACAADAABAAABAA";
let pat = "AABA";
search(pat, txt);
输出:
在索引 0 处找到模式
在索引 9 处找到模式
在索引 13 处找到模式
时间复杂度: O(N*M) 辅助空间: O(1)
KMP算法用于在“文本”中查找“模式”。该算法从左到右逐个字符进行比较。但每当发生不匹配时,它都会使用一个名为“前缀表”的预处理表来跳过匹配时的字符比较。有时前缀表也称为LPS表。这里 LPS 代表“最长的正确前缀,也是后缀”。
我们使用LPS表来决定当发生不匹配时要跳过多少个字符进行比较。 当发生不匹配时,检查模式中不匹配字符的前一个字符的 LPS 值。如果为“0”,则开始将模式的第一个字符与下一个字符与文本中不匹配的字符进行比较。如果它不是“0”,则开始将索引值等于前一个字符的LPS值的字符与模式中的不匹配字符与文本中的不匹配字符进行比较。
KMP算法示例
从左到右比较模式的第一个字符与文本的第一个字符
将模式的第一个字符与文本的下一个字符进行比较
比较模式[0]和模式[1]值
将模式[0] 与文本中的下一个字符进行比较。
将模式[2] 与文本中不匹配的字符进行比较。
让我们看一下 KMP 算法在文本中查找模式的工作示例。
脂多糖表
定义变量
比较 A 和 B
比较 A 和 C
比较 A 和 D
比较 A 与 A
将 B 与 B 进行比较
比较 C 和 D
比较 A 和 D
KMP算法的实现:
// 在 pat[] 中出现 txt[] 的次数
function computeLPSArray(pat, M, lps)
{
// 前一个最长前缀后缀的长度
let len = 0;
lps[0] = 0;
// 循环计算 lps[i],其中 i 的取值范围为 1 到 M-1
let i = 1;
while (i < M) {
if (pat[i] == pat[len]) {
len++;
lps[i] = len;
i++;
}
else // (pat[i] != pat[len])
{
// This is tricky. Consider the example.
// AAACAAAA and i = 7. The idea is similar
// to search step.
if (len != 0) {
len = lps[len - 1];
// 另外,请注意我们在这里不递增 i
}
else // if (len == 0)
{
lps[i] = 0;
i++;
}
}
}
}
function KMPSearch(pat, txt) {
let M = pat.length;
let N = txt.length
// 创建一个lps[]数组,用于存储模式的最长前缀后缀值
let lps = [];
// Preprocess the pattern (calculate lps[] array)
computeLPSArray(pat, M, lps);
let i = 0; // index for txt[]
let j = 0; // index for pat[]
while ((N - i) >= (M - j)) {
if (pat[j] == txt[i]) {
j++;
i++;
}
if (j == M) {
console.log("Found pattern at index:", i - j);
j = lps[j - 1];
}
// mismatch after j matches
else if (i < N && pat[j] != txt[i])
{
// 不要匹配 lps[0..lps[j-1]] 个字符,
// 它们无论如何都会匹配
if (j != 0) {
j = lps[j - 1];
} else {
i = i + 1;
}
}
}
}
// 为给定的模式pat[0..M-1]填充lps[]
// 测试上述函数的驱动程序
let txt = "ABABDABACDABABCABAB";
let pat = "ABABCABAB";
KMPSearch(pat, txt);
输出
在索引 10 处找到模式
时间复杂度: O(n + m) 辅助空间: O(M)