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

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

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

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

模式搜索算法的特点:

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

朴素模式搜索算法

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

朴素模式搜索方法的时间复杂度为 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)

相关推荐
Xua305523 分钟前
浅谈Spring Cloud:OpenFeign
后端·spring·spring cloud
小鼠米奇24 分钟前
详解Ajax与axios的区别
前端·javascript·ajax
Bunury33 分钟前
Vue3新组件transition(动画过渡)
前端·javascript·vue.js
zero.cyx38 分钟前
JS函数部分
开发语言·前端·javascript
超级小的大杯柠檬水39 分钟前
SpringBoot lombok(注解@Getter @Setter)
java·前端·spring
AvatarGiser1 小时前
《ElementUI/Plus 踩坑》el-table + sortablejs 拖拽顺序错乱(Vue2/3适用)
前端·vue.js·elementui
蓝染-惣右介1 小时前
【若依RuoYi-Vue | 项目实战】帝可得后台管理系统(二)
java·前端·后端·vue·springboot
齐 飞1 小时前
Java接口和抽象类的区别
java·笔记·后端
哈哈哈哈cwl1 小时前
秒懂Vue.jsDiff算法与虚拟DOM
前端·javascript·vue.js
打鱼又晒网1 小时前
你了解system V的ipc底层如何设计的吗?消息队列互相通信的原理是什么呢?是否经常将信号量和信号混淆呢?——问题详解
linux·运维·服务器·后端·操作系统