模式搜索简介 - 数据结构和算法教程

模式搜索简介 - 数据结构和算法教程

模式搜索是一种涉及搜索字符串、单词、图像等模式的算法。

我们使用某些算法来进行搜索过程。模式搜索的复杂性因算法而异。在数据库中执行搜索时它们非常有用。模式搜索算法对于在较大字符串的子字符串中查找模式非常有用。这个过程可以使用我们将在本文章中讨论的各种算法来完成。

模式搜索算法的特点:

  • 模式搜索算法应该快速准确地识别熟悉的模式。
  • 识别并分类不熟悉的模式。
  • 即使部分隐藏,也能识别模式。
  • 轻松、自动地快速识别模式。

朴素模式搜索算法

朴素模式搜索是其他模式搜索算法中最简单的方法。它检查模式中主字符串的所有字符。该算法对于较小的文本很有帮助。它不需要任何预处理阶段。我们可以通过检查一次字符串来找到子字符串。它也不占用额外的空间来执行操作。

朴素模式搜索方法的时间复杂度为 O(m*n)。m 是模式的大小,n 是主字符串的大小。

ini 复制代码
 // 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算法

KMP算法用于在"文本"中查找"模式"。该算法从左到右逐个字符进行比较。但每当发生不匹配时,它都会使用一个名为"前缀表"的预处理表来跳过匹配时的字符比较。有时前缀表也称为LPS表。这里 LPS 代表"最长的正确前缀,也是后缀"。

如何使用 LPS 表

我们使用LPS表来决定当发生不匹配时要跳过多少个字符进行比较。 当发生不匹配时,检查模式中不匹配字符的前一个字符的 LPS 值。如果为"0",则开始将模式的第一个字符与下一个字符与文本中不匹配的字符进行比较。如果它不是"0",则开始将索引值等于前一个字符的LPS值的字符与模式中的不匹配字符与文本中的不匹配字符进行比较。

KMP算法示例

从左到右比较模式的第一个字符与文本的第一个字符

将模式的第一个字符与文本的下一个字符进行比较

比较模式0和模式1

将模式0 与文本中的下一个字符进行比较。

将模式2 与文本中不匹配的字符进行比较。

KMP 算法的工作原理

让我们看一下 KMP 算法在文本中查找模式的工作示例。

脂多糖表

定义变量

比较 A 和 B

比较 A 和 C

比较 A 和 D

比较 A 与 A

将 B 与 B 进行比较

比较 C 和 D

比较 A 和 D

KMP算法的实现:

JavaScript

ini 复制代码
 // 在 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)

相关推荐
楚宝ovo1 分钟前
新增一个 demo 子应用 - 微前端
前端
渔夫正在掘金16 分钟前
Cordis 插件热插拔能力深度解析
后端·node.js
不爱编程的小九九21 分钟前
小九源码-springboot004-springboot智能阅读推荐系统
java·spring boot·后端
码事漫谈33 分钟前
为什么调试模式不崩溃,打包后却崩溃了?
后端
JarvanMo1 小时前
Dart 3.13:小版本,大动作
前端
纯粹的热爱1 小时前
Ubuntu 安装 Node.js 22.x(通过 NodeSource 官方源)
前端
Highcharts1 小时前
如何选择正确的图表:驱动理解和洞察力的三部分框架(第3部分)
前端·数据可视化
智驭未来掌门人1 小时前
利用FFmpeg快速实现一个RTSP推流服务器
后端
垚垚学技术_聚焦云原生1 小时前
K8s Pod 完整生命周期详解
后端
JavaGuide1 小时前
Github 史诗级故障,与此同时,Cursor 版「GitHub」正式上线!
前端·后端