关于KMP算法和BM算法的理解

合集下载

KMP讲解

KMP讲解
2.2、kmp算法
有了覆盖函数,那么实现kmp算法就是很简单的了,我们的原则还是从左向右匹配,但是当失配发生时,我们不用把target_index向回移动,target_index前面已经匹配过的部分在pattern自身就能体现出来,只要动pattern_index就可以了。
当发生在j长度失配时,只要把pattern向右移动j-overlay(j)长度就可以了。
说了这么半天那么这种方法是什么呢,这种方法是就大名鼎鼎的确定的有限自动机(Deterministic finite state automaton DFA),DFA可识别的文法是3型文法,又叫正规文法或是正则文法,既然可以识别正则文法,那么识别确定的字串肯定不是问题(确定字串是正则式的一个子集)。对于如何构造DFA,是有一个完整的算法,这里不做介绍了。在识别确定的字串时使用DFA实在是大材小用,DFA可以识别更加通用的正则表达式,而用通用的构建DFA的方法来识别确定的字串,那这个overhead就显得太大了。
{
index = overlay_value[index];
}
if(pattern[index+1]==pattern[i])
{
overlay_value[i] = index +1;
KMP 算法可在O(n+m)时间内完成全部的串的模式匹配工作。
ok,最后给出KMP算法实现的c++代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int kmp_find(const string& target,const string& pattern)

文本匹配算法的优化策略与应用

文本匹配算法的优化策略与应用

文本匹配算法的优化策略与应用随着信息爆炸时代的到来,人们需要处理和理解大量的文本数据。

文本匹配算法的优化策略与应用因此变得尤为重要。

本文将探讨一些常见的文本匹配算法,以及如何优化这些算法以提高其效率和准确性。

一、基础算法介绍1.1 精确匹配算法精确匹配算法是最简单的文本匹配算法之一,它通过逐个比较文本中的字符来确定匹配程度。

这种算法的优点是简单易懂,但其缺点是效率较低,尤其是在处理大规模文本数据时。

1.2 KMP算法KMP算法是一种改进的文本匹配算法,它通过预处理模式串,利用已经匹配过的信息来减少不必要的比较次数。

KMP算法在处理大规模文本数据时具有较高的效率,但其空间复杂度较高。

1.3 BM算法BM算法是一种基于后缀匹配的文本匹配算法,它通过从模式串末尾开始匹配,利用模式串中的字符出现位置来快速跳过不匹配的字符。

BM算法在处理大规模文本数据时具有较高的效率和较低的空间复杂度。

二、优化策略2.1 基于索引的优化基于索引的优化策略是通过建立文本的索引结构,提高匹配算法的效率。

常见的索引结构有倒排索引、前缀树和后缀树等。

这些索引结构可以帮助我们快速定位关键词的位置,从而提高匹配的速度。

2.2 基于语义的优化基于语义的优化策略是通过理解文本的语义信息,提高匹配算法的准确性。

常见的语义分析方法有词向量模型和主题模型等。

这些方法可以帮助我们更好地理解文本的含义,从而提高匹配的准确性。

2.3 基于机器学习的优化基于机器学习的优化策略是通过训练模型,提高匹配算法的准确性和泛化能力。

常见的机器学习算法有支持向量机、决策树和深度学习等。

这些算法可以通过学习大量的文本数据,自动提取特征并进行匹配。

三、应用场景3.1 文本检索文本检索是文本匹配算法的一种重要应用场景。

通过优化算法和建立索引结构,可以提高文本检索的速度和准确性。

例如,在搜索引擎中,我们可以根据用户输入的关键词,快速找到相关的文本信息。

3.2 自然语言处理自然语言处理是另一个重要的文本匹配应用场景。

关键字匹配函数

关键字匹配函数

关键字匹配函数
在计算机科学中,关键字匹配函数通常用于在文本或数据集中查找特定的关键字或模式。

这些函数可以用于各种应用,如搜索引擎、数据挖掘、自然语言处理等。

以下是一些常见的关键字匹配函数的示例:
1.朴素字符串匹配(Naive String Matching):这是最简单的关键字匹配算法,它逐个比较文本中的每个字符与目标关键字。

时间复杂度为O(n),其中n是文本的长度。

2.KMP算法(Knuth-Morris-Pratt算法):KMP算法是一种改进的字符串匹配算法,它通过预处理目标关键字来减少比较次数。

时间复杂度为O(n+m),其中n是文本的长度,m是目标关键字的长度。

3.BM算法(Boyer-Moore算法):BM算法也是一种改进的字符串匹配算法,它通过构建坏字符规则和好后缀规则来减少比较次数。

时间复杂度为O(n+m)。

4.AC自动机(Aho-Corasick算法):AC自动机是一种多模式字符串匹配算法,它通过构建Trie树和失配指针来同时匹配多个关键字。

时间复杂度为O(m),其中m是关键字的数量。

5.KMP算法的变种:有一些基于KMP算法的变种,如Sunday算法、逆Sunday算法等,它们通过不同的方式来预处理目标关键字,以减少比较次数。

这些函数都有各自的优点和缺点,选择哪种函数取决于具体的应用场景和需求。

例如,对于小文本和短关键字,朴素字符串匹配可
能足够快;对于大文本和长关键字,KMP、BM或AC自动机可能更有效。

kmp算法概念

kmp算法概念

kmp算法概念KMP算法概念KMP算法是一种字符串匹配算法,它的全称是Knuth-Morris-Pratt 算法。

该算法通过预处理模式串,使得在匹配过程中避免重复比较已经比较过的字符,从而提高了匹配效率。

一、基本思想KMP算法的基本思想是:当模式串与文本串不匹配时,不需要回溯到文本串中已经比较过的位置重新开始匹配,而是利用已知信息跳过这些位置继续匹配。

这个已知信息就是模式串自身的特点。

二、next数组1.定义next数组是KMP算法中最核心的概念之一。

它表示在模式串中当前字符之前的子串中,有多大长度的相同前缀后缀。

2.求解方法通过观察模式串可以发现,在每个位置上出现了相同前缀和后缀。

例如,在模式串“ABCDABD”中,第一个字符“A”没有任何前缀和后缀;第二个字符“B”的前缀为空,后缀为“A”;第三个字符“C”的前缀为“AB”,后缀为“B”;第四个字符“D”的前缀为“ABC”,后缀为“AB”;第五个字符“A”的前缀为“ABCD”,后缀为“ABC”;第六个字符“B”的前缀为“ABCDA”,后缀为“ABCD”;第七个字符“D”的前缀为“ABCDAB”,后缀为“ABCDA”。

根据上述观察结果,可以得到一个求解next数组的方法:(1)next[0]=-1,next[1]=0。

(2)对于i=2,3,...,m-1,求解next[i]。

①如果p[j]=p[next[j]],则next[i]=next[j]+1。

②如果p[j]≠p[next[j]],则令j=next[j],继续比较p[i]和p[j]。

③重复执行步骤①和步骤②,直到找到满足条件的j或者j=-1。

(3)通过上述方法求解出所有的next值。

三、匹配过程在匹配过程中,文本串从左往右依次与模式串进行比较。

如果当前字符匹配成功,那么继续比较下一个字符;否则利用已知信息跳过一些位置继续进行匹配。

具体地:(1)如果当前字符匹配成功,则i和j都加1。

(2)如果当前字符匹配失败,则令j=next[j]。

BF算法KMP算法BM算法

BF算法KMP算法BM算法

BF算法KMP算法BM算法BF算法(Brute-Force Algorithm)是一种简单直接的字符串匹配算法,也称为朴素算法。

BF算法的基本思想是从主串的第一个字符开始,每次移动一个字符,然后和模式串进行逐个字符比较,如果不匹配,则继续下一个位置的比较。

如果字符匹配,则比较下一个字符,直到找到完全匹配的子串或者主串遍历结束。

BF算法的时间复杂度为O(m*n),其中m和n分别为主串和模式串的长度。

当主串和模式串的长度较小时,BF算法是一个简单高效的字符串匹配算法。

然而,当主串和模式串的长度非常大时,BF算法的效率会非常低下。

KMP算法(Knuth-Morris-Pratt Algorithm)是一种改进的字符串匹配算法。

KMP算法的核心思想是利用已经匹配过的部分信息来避免不必要的字符比较。

KMP算法通过构建一个跳转表(也称为失配函数),记录当前位置之前的字符中可能出现的最大公共前后缀长度。

根据跳转表的信息,在模式串和主串不匹配时,可以直接跳过一些字符,继续比较下一个字符。

KMP算法的时间复杂度为O(m+n),其中m和n分别为主串和模式串的长度。

KMP算法在主串长度较大时,相对于BF算法有较高的效率。

它的空间复杂度为O(k),其中k为模式串的长度,用于存储跳转表。

BM算法(Boyer-Moore Algorithm)是一种更为高效的字符串匹配算法。

BM算法的核心思想是尽可能地跳过更多的字符,而不是每次只移动一个字符。

BM算法借助两个启发式规则(坏字符规则和好后缀规则)来确定移动的步长。

坏字符规则根据字符在模式串中的位置,找到离坏字符最近的下标位置,从而确定移动的步长;好后缀规则根据已经匹配的后缀子串,找到离该子串最近的下标位置,从而确定移动的步长。

BM算法的时间复杂度为O(m+n),其中m和n分别为主串和模式串的长度。

BM算法在处理文本串相对固定的情况下有较高的效率,但是在模式串较短,主串较长的情况下,BM算法并不一定比KMP算法更高效。

字符串匹配问题的算法步骤

字符串匹配问题的算法步骤

字符串匹配问题的算法步骤字符串匹配是计算机科学中常见的问题,主要用于确定一个字符串是否包含另一个字符串。

解决这个问题的算法可以分为暴力匹配算法、Knuth-Morris-Pratt(KMP)算法和Boyer-Moore(BM)算法等。

暴力匹配算法是最简单的一种方法。

它的基本思想是从主串的第一个字符开始,依次和模式串的每个字符进行比较,直到找到一个字符不匹配为止。

如果找到了不匹配的字符,则将主串的指针后移一位,重新开始匹配。

如果匹配成功,模式串的指针向后移一位,主串的指针也向后移一位,继续匹配。

这个过程一直进行下去,直到模式串的指针到达模式串的末尾,或者找到了一个匹配的子串。

尽管暴力匹配算法很简单,但是它的时间复杂度较高,为O(m*n),其中m是主串的长度,n是模式串的长度。

当主串和模式串很长时,暴力匹配算法的效率就会很低。

为了提高字符串匹配的效率,有很多其他的算法被提出。

其中比较著名的是KMP算法和BM算法。

KMP算法的核心思想是,当发生不匹配的情况时,不需要回溯主串的指针,而是通过已经匹配的部分字符的信息,将模式串的指针移动到一个新的位置,从而避免了不必要的比较。

具体来说,KMP算法在匹配的过程中,通过建立一个部分匹配表(Partial Match Table),来记录模式串中每个位置的最长前缀后缀的长度。

当发生不匹配的情况时,根据部分匹配表的信息,可以将模式串的指针直接移动到下一个可能匹配的位置。

BM算法是一种基于启发式的匹配算法,它的核心思想是从模式串的尾部开始匹配,并根据已经匹配的部分字符的信息,跳跃式地移动模式串的指针。

具体来说,BM算法分别构建了坏字符规则和好后缀规则。

坏字符规则用于处理主串中与模式串不匹配的字符,找到最右边的该字符在模式串中的位置,并移动模式串的指针到对齐该字符。

好后缀规则用于处理主串中与模式串匹配的部分,找到最右边的该部分在模式串中的位置,并移动模式串的指针到对齐该部分。

BM算法讲解

BM算法讲解

由于毕业设计(入侵检测)的需要,这两天仔细研究了BM模式匹配算法,稍有心得,特此记下。

首先,先简单说明一下有关BM算法的一些基本概念。

BM算法是一种精确字符串匹配算法(区别于模糊匹配)。

BM算法采用从右向左比较的方法,同时应用到了两种启发式规则,即坏字符规则和好后缀规则,来决定向右跳跃的距离。

BM算法的基本流程: 设文本串T,模式串为P。

首先将T与P进行左对齐,然后进行从右向左比较,如下图所示:若是某趟比较不匹配时,BM算法就采用两条启发式规则,即坏字符规则和好后缀规则,来计算模式串向右移动的距离,直到整个匹配过程的结束。

下面,来详细介绍一下坏字符规则和好后缀规则。

首先,诠释一下坏字符和好后缀的概念。

请看下图:图中,第一个不匹配的字符(红色部分)为坏字符,已匹配部分(绿色)为好后缀。

1)坏字符规则(Bad Character):在BM算法从右向左扫描的过程中,若发现某个字符x不匹配,则按如下两种情况讨论:i. 如果字符x在模式P中没有出现,那么从字符x开始的m个文本显然不可能与P匹配成功,直接全部跳过该区域即可。

ii. 如果x在模式P中出现,则以该字符进行对齐。

用数学公式表示,设Skip(x)为P右移的距离,m为模式串P的长度,max(x)为字符x在P中最右位置。

例1:下图红色部分,发生了一次不匹配。

计算移动距离Skip(c) = 5 - 3 = 2,则P向右移动2位。

移动后如下图:2)好后缀规则(Good Suffix):若发现某个字符不匹配的同时,已有部分字符匹配成功,则按如下两种情况讨论:i. 如果在P中位置t处已匹配部分P'在P中的某位置t'也出现,且位置t'的前一个字符与位置t的前一个字符不相同,则将P右移使t'对应t方才的所在的位置。

ii. 如果在P中任何位置已匹配部分P'都没有再出现,则找到与P'的后缀P''相同的P的最长前缀x,向右移动P,使x对应方才P''后缀所在的位置。

字符串快速匹配算法

字符串快速匹配算法

字符串快速匹配算法字符串快速匹配算法,指的是在一个文本串中查找一个模式串的过程。

在计算机科学中,字符串匹配是一种基本的问题,在许多应用中都有广泛的应用,比如:文本编辑器、数据压缩、网络安全等等。

传统的字符串匹配算法,如朴素匹配算法和KMP算法,虽然可行,但是时间复杂度较高,对于大规模数据匹配效率较低。

为了提高字符串匹配效率,人们提出了许多快速匹配算法,如BM算法、Sunday算法、AC自动机等等。

BM算法是一种基于后缀匹配思想的快速字符串匹配算法,它的核心思想是在匹配的过程中,根据模式串的后缀字符来确定跳过的字符数。

BM算法的时间复杂度为O(n/m),其中n为文本串的长度,m为模式串的长度,因此它可以在较短的时间内完成匹配任务。

BM算法的实现过程较为复杂,但是由于其高效性,被广泛应用于实际工程中。

Sunday算法是一种基于贪心思想的快速字符串匹配算法,它的核心思想是在匹配的过程中,每次从模式串的末尾开始比较,如果匹配成功,则直接返回匹配位置,否则通过预处理模式串中的字符来确定跳过的字符数。

Sunday算法的时间复杂度为O(n/m),其中n 为文本串的长度,m为模式串的长度,因此它也可以在较短的时间内完成匹配任务。

Sunday算法的实现过程相对简单,适用于短模式串和长文本串的匹配。

AC自动机是一种基于字典树的快速字符串匹配算法,它的核心思想是将所有模式串构建成一个AC自动机,然后在文本串中进行匹配。

AC自动机的时间复杂度为O(n+k),其中n为文本串的长度,k为模式串的总长度,因此它可以在非常短的时间内完成匹配任务。

AC 自动机的实现过程比较复杂,但是由于其高效性,被广泛应用于网络安全和搜索引擎等领域。

除了上述几种算法,还有许多其他的快速字符串匹配算法,如RK 算法、Trie树、后缀树等等。

这些算法各有特点,适用于不同的场景和数据类型。

在实际应用中,我们需要根据具体的需求和数据特征,选择合适的算法来完成字符串匹配任务。

K M 算 法 详 解

K M 算 法 详 解

BM算法详解1977年,德克萨斯大学的Robert S. Boyer教授和J Strother Moore 教授发明了一种新的字符串匹配算法:Boyer-Moore算法,简称BM算法。

该算法从模式串的尾部开始匹配,且拥有在最坏情况下O(N)的时间复杂度。

一般情况下,比KMP算法快3-5倍。

BM算法在移动模式串的时候是从左到右,而进行比较的时候是从右到左的。

常规的匹配算法移动模式串的时候是从左到右,而进行比较的时候也是是从左到右的。

BM算法思想:BM算法实际上包含两个并行的算法,坏字符算法和好后缀算法。

这两种算法的目的就是让模式串每次向右移动尽可能大的距离。

BM算法定义了两个规则:坏字符规则:当文本串中的某个字符跟模式串的某个字符不匹配时,我们称文本串中的这个失配字符为坏字符,此时模式串需要向右移动,移动的位数 = 坏字符在模式串中的位置 - 坏字符在模式串中最右出现的位置。

此外,如果"坏字符"不包含在模式串之中,移动的长度为模式串的长度。

好后缀规则:当字符失配时,按好后缀算法计算模式串需要向右移动的距离,要借助BmGs数组BmGs数组的定义,分三种情况。

为了实现好后缀规则,需要定义一个数组suffix[],其中suffix[i] = s 表示以i为边界,与模式串后缀匹配的最大长度,如下图所示,用公式可以描述:满足P[i-s, i] == P[m-s, m]的最大长度s。

1、模式串中没有子串匹配上后后缀,并且在模式串中找不到最长前缀,让该前缀等于好后缀的后缀。

此时,直接移动模式到好后缀的下一个字符2、对应好后缀算法:如下图:模式串中有子串匹配上好后缀。

3、模式串中没有子串匹配上后后缀,此时需要寻找模式串的一个最长前缀,并让该前缀等于好后缀的后缀,寻找到该前缀后,让该前缀和好后缀对齐即可。

注意这种情况:模式串:bcbcgfdabcbcsuff[3]=4 suff[1]=2bmGs[0.7]=8;bmGs[8.9]=10;--与最右边的进行比配,所以要移动距离小?#includeiostream#includestring.h#includestdio.h#define SIZE 26using namespace std;int max(int a,int b)return ab?a:b;--1、字符在模式串中有出现。

kmp算法bm算法

kmp算法bm算法

kmp算法bm算法
KMP算法和BM算法都是字符串匹配算法,用于在一个主串中查找特定的子串。

两者的不同点在于匹配失败时如何利用已匹配成功的信息进行下一次匹配。

KMP算法全称为Knuth-Morris-Pratt算法,是由Donald Knuth、James H. Morris和Vaughan Pratt于1977年联合发表的。

其核心思想是利用已经匹配成功的信息来消除无用的匹配。

具体实现中,KMP算法使用一个前缀函数数组F来记录每个子串的前缀中最长的既是该子串的真前缀又是该子串的真后缀的长度,若在匹配中出现了失配,则可利用前缀函数的信息进行跳转,以避免重复的匹配。

KMP算法在理论和实践中均有很高的效率和广泛的应用,例如在文本编辑器和编译器中常常使用KMP算法来实现查找和替换的功能。

BM算法全称为Boyer-Moore算法,是由Robert S. Boyer和J Strother Moore于1977年发明的另一个字符串匹配算法。

BM算法的核心思想是从模式串的末尾逐个比较主串中的字符,若出现不匹配的字符,则尽可能地利用模式串中已经匹配的字符的关系向后滑动模式串,以尽可能地跳过不符合条件的情况。

BM算法相对于KMP算法的优点是更适合处理大量字符集的情况,并且在某些情况下能够比KMP算法更快地匹配。

BM算法也被广泛地应用在文本搜索和文件压
缩等领域。

两种算法各有优劣,可以针对不同的应用场景选择不同的算法来实现字符串匹配。

在实际使用中,如果主串和模式串的长度都比较小,那么KMP算法相对来说比较简单实用,而如果主串或模式串的长度非常长或者字符集非常大,那么BM算法的效率可能更高,可以采用BM 算法来实现字符串匹配。

三种模式匹配算法的比较和分析

三种模式匹配算法的比较和分析

三种模式匹配算法的比较和分析在计算机科学中,模式匹配是指在一个较大的文本串中查找一个较小的模式串。

模式匹配算法的目标是找到模式串在文本串中的位置,或者确定模式串是否在文本串中出现。

模式匹配在很多应用中都有广泛的应用,例如字符串匹配、文本、图像处理等领域。

常见的模式匹配算法有三种:朴素算法、KMP算法和Boyer-Moore算法。

下面将对这三种算法进行比较和分析。

1.朴素算法:朴素算法又称为暴力算法,是一种简单直接的模式匹配算法。

它的基本思想是从文本串的第一个字符开始,逐个比较文本串和模式串的字符,如果字符不匹配则向右移动一位,继续比较下一个字符。

朴素算法的时间复杂度为O(m*n),其中m为文本串的长度,n为模式串的长度。

朴素算法的优点是实现简单,不需要额外的空间。

但是朴素算法的性能较低,当文本串和模式串都很长时,需要进行大量的字符比较,效率较低。

2.KMP算法:KMP算法是一种改进的模式匹配算法,它利用了模式串自身的信息来加快匹配过程。

KMP算法的核心思想是利用已经匹配过的信息,尽量减少无效的比较。

KMP算法通过建立一个模式串的前缀表,记录模式串中每个位置的最长可匹配前缀子串的长度。

在匹配过程中,当遇到不匹配的字符时,根据前缀表中的信息,将模式串移动到一个合适的位置,继续匹配。

KMP算法的时间复杂度为O(m+n),其中m为文本串的长度,n为模式串的长度。

KMP算法利用了模式串自身的信息,避免了不必要的字符比较,因此相对于朴素算法,它具有更高的匹配效率。

3. Boyer-Moore算法:Boyer-Moore算法是一种高效的模式匹配算法,经常被应用于大规模数据的。

Boyer-Moore算法利用了模式串和文本串中的字符比较结果,通过适当的移动算法,提前排除一部分不匹配的位置。

Boyer-Moore算法的核心思想是从模式串的末尾开始匹配,每次从右到左比较,一旦发现不匹配的字符,就利用模式串中已经匹配过的字符的信息,将模式串向右移动一定的距离。

KMP算法个人感悟

KMP算法个人感悟

KMP算法个⼈感悟 既然来到了这,那也⼀定是被KMP困惑了⼀阵的⼩伙伴。

虽然这篇⽂章也不⼀定让你能看懂,但是这算是我⾃⼰个⼈对于KMP的最直接的理解,也许不好,也许有误,望⼤佬指出。

对于串的模式匹配的算法很多,当然最简单就是暴⼒破解法(也即是BF算法),由此我们从这开始引⼊ BF算法原理就是将主串和模式串依次进⾏⽐较,若遇到不同的时候,主串和模式串都会回溯(也许开始这会有点迷,但是没影响,后⾯⾃然会理解)如 我们将模式串和主串开始依次⽐较,第⼀个都不相同,很简单的就是直接⽤模式串和第⼀个和主串的第⼆个开始⽐较,如下 就这样依次⽐较,我们会发现前四个都是不⾏的(包括其中的⼀个括号),因此我们就直接从第五个开始⽐较 我们会发现从模式串的A到B都是相同的,所以直接跳过到不同的位置⽐较时吧 这是主串和模式串已经出现了不同,于是我们要开始考虑下⼀步怎么做。

很容易就会想到我们再拿模式串的第⼀个和主串刚才最开始⽐较的地⽅的下⼀个重新开始⽐较,如下 这⼀步的这个过程就叫做回溯 但是我们会发现⼀个问题因为我们开始匹配成功时已经就确定了前⾯的位置的字母了,我们将主串回溯和模式串的开头重新⽐较肯定会失败,这就会浪费很多的时间。

那我们仔细的观察就会发现,当我们匹配失败后可以直接将模式串的第三个和主串失配的位置重新开始⽐较,这样就不⽤回溯主串的指针了,也不⽤将模式串的指针回溯到头了,可以节约不少时间。

这也就是KMP算法的思路。

但是为什么要从模式串的第三个位置开始⽐较呢? 我们想想这幅图 当我们匹配到这个地步了,发现不匹配,相当于我们前⾯的匹配成功的主串是和模式串相同的,也就是说我们是知道了这⼀部分主串的样⼦的,我们确切的知道它们每个位置的字符,因此肯定不会去拿⼀个不⼀样的字符去⽐较,这就是浪费时间的作为。

所以我们就会寻找其中相同的⼦串,并根据这个将模式串指针回溯到合适的位置进⾏⽐较。

如上⾯这中情况,我们肯定就会从模式串的第三个位置开始⽐较,因为我们会发现前⾯的部分其中有前缀AB和后缀AB是相同,因此如下图 KMP算法 到了这⾥,我们就可以认真的分析KMP算法的步骤了 ⾸先,我们会将模式串和主串依次⽐较 然后,若我们遇到了匹配失败的时候,就保持主串的指针不动,尽可能的将模式串向右滑动(即回溯模式串的指针i),回溯到哪⾥呢就要看后⾯的next数组,即回溯到对应的next数组的值那⾥ 最后,直到匹配成功或者主串长度不够匹配失败 那么就还有最后⼀个也是最重要的⼀个问题了:匹配失败的时候到底将i回溯到哪个位置,怎么计算,计算机肯定不会像我们⼤脑那么去思考,所以需要我们告诉它 注意:本⽂接下来的数组相关的是由严⽼的为准,即数组的第⼀个位置不存放元素(应该很多⼈也都是⽤的这个教材) 我们解决这个回到哪⾥的问题,我们发现我们思考的时候是找到了前后缀的最长公共元素长度,那我们就来思考如何寻找这个,然后告诉计算机不就⾏了吗 注:这⾥的前后缀表⽰是⼩于串本⾝长度的 举例: 对于⼀个串ABABC 开始寻找 A--0 AB--0 ABA--1 ABAB--2 ABABC--0 就会得到这么⼀个公共最长前后缀的表 但是这也会有⼀些不对,例如我们匹配到了C这⼀步失配,这个表会让我们再次从0开始⽐较,但这显然不对,因为前⾯都是AB,因此我们应当从第三个开始⽐较,所以KMP算法基于这个表做了操作,也就形成了⼤家所知的next数组 next数组 对于next数组,我们第⼀个元素肯定是为0,第⼆个元素是为1(先别疑惑,听我慢慢道来)(当然再提醒⼀下这⾥的数组是从1号位置开始存放数据的) ⼤家想想,若当前的主串⽐较的位置和模式串的第⼀个位置都不匹配怎么办?当然BF是直接将主串指针j后移,然后⽐较。

K M P 算 法 详 解

K M P 算 法 详 解

KMP算法详解(转)此前一天,一位MS的朋友邀我一起去与他讨论快速排序,红黑树,字典树,B树、后缀树,包括KMP算法,唯独在讲解KMP算法的时候,言语磕磕碰碰,我想,原因有二:1、博客内的东西不常回顾,忘了不少;2、便是我对KMP算法的理解还不够彻底,自不用说讲解自如,运用自如了。

所以,特再写本篇文章。

由于此前,个人已经写过关于KMP算法的两篇文章,所以,本文名为:KMP算法之总结篇。

本文分为如下六个部分:第一部分、再次回顾普通的BF算法与KMP算法各自的时间复杂度,并两相对照各自的匹配原理;第二部分、通过我此前第二篇文章的引用,用图从头到尾详细阐述KMP算法中的next数组求法,并运用求得的next数组写出KMP算法的源码;第三部分、KMP算法的两种实现,代码实现一是根据本人关于KMP算法的第二篇文章所写,代码实现二是根据本人的关于KMP算法的第一篇文章所写;第四部分、测试,分别对第三部分的两种实现中next数组的求法进行测试,挖掘其区别之所在;第五部分、KMP完整准确源码,给出KMP算法的准确的完整源码;第六步份、一眼看出字符串的next数组各值,通过几个例子,让读者能根据字符串本身一眼判断出其next数组各值。

力求让此文彻底让读者洞穿此KMP算法,所有原理,来龙去脉,让读者搞个通通透透(注意,本文中第二部分及第三部分的代码实现一的字符串下标i从0开始计算,其它部分如第三部分的代码实现二,第五部分,和第六部分的字符串下标i 皆是从1开始的)。

第一部分、KMP算法初解1、普通字符串匹配BF算法与KMP算法的时间复杂度比较KMP算法是一种线性时间复杂的字符串匹配算法,它是对BF算法(Brute-Force,最基本的字符串匹配算法的)改进。

对于给的原始串S 和模式串P,需要从字符串S中找到字符串P出现的位置的索引。

BF算法的时间复杂度O(strlen(S) * strlen(T)),空间复杂度O(1)。

BF算法KMP算法BM算法

BF算法KMP算法BM算法

BF算法KMP算法BM算法1. BF算法(Brute Force Algorithm)BF算法也称为暴力匹配算法,它是一种最简单直观的字符串匹配算法。

其原理是从目标字符串的第一个字符开始,逐个与模式字符串的字符进行比较,如果匹配失败,则将目标字符串的指针向后移动一位,再继续比较。

直到找到匹配或目标字符串被遍历完。

BF算法的时间复杂度为O(n*m),其中n为目标字符串的长度,m为模式字符串的长度。

在最坏情况下,需要进行n-m+1次比较。

BF算法的优点是实现简单,适用于简单的字符串匹配问题。

但是对于大规模文本的匹配效率较低。

2. KMP算法(Knuth–Morris–Pratt Algorithm)KMP算法是一种改进的字符串匹配算法,通过利用已经匹配的信息来避免不必要的比较。

它首先构建一个部分匹配表(Partial Match Table),用于存储模式字符串每个前缀的最长公共前后缀的长度。

然后通过这个表来指导匹配过程。

KMP算法的核心思想是,当出现不匹配的字符时,通过部分匹配表中的信息,可以将模式字符串向后移动尽可能多的位置,而不是单纯地移动一位。

这样可以大大减少不必要的比较次数,提高匹配效率。

KMP算法的时间复杂度为O(n+m),其中n为目标字符串的长度,m为模式字符串的长度。

在构建部分匹配表时需要O(m)的时间复杂度,匹配过程需要O(n)的时间复杂度。

KMP算法的优点是在大规模文本匹配时效率较高,缺点是算法较为复杂,需要额外的存储空间来存储部分匹配表。

3. BM算法(Boyer-Moore Algorithm)BM算法是一种高效的字符串匹配算法,通过利用不匹配字符的信息来跳过尽可能多的字符,从而减少比较次数。

其核心思想是从模式字符串的末尾开始匹配,并向前移动模式字符串。

BM算法分为坏字符规则和好后缀规则两部分:-坏字符规则:当遇到不匹配的字符时,将模式字符串根据目标字符串中的字符向后移动一位,从而跳过了部分字符的比较。

那些经典算法:字符串匹配算法BM算法

那些经典算法:字符串匹配算法BM算法

那些经典算法:字符串匹配算法BM算法单模式串匹配算法中BM(Boyer-Moore)算法算是很难理解的算法了,不过性能高效,据说比KMP算法性能提升3到4倍,suricata里面的单模式匹配就是用这种算法,所以有必要学习下,再把suricata的这部分代码过一下还是不错的。

一、BM算法原理BM算法是1975年发明的,它是一种后匹配算法,我们普通的字符串匹配算法是从左向右的,BM算法是从右向做的,即先判断模式串最后一个字符是否匹配,最后判断模式串第一个字符是否匹配。

原来我们在BF算法中,如果模式串和主串不匹配,则将主串或模式串后移一位继续匹配,BM算法根据模式串的特定规律,将后移一位的步子迈的更大一些,后移几位。

来看个图简单说明下,图来自《数据结构与算法之美》课程:但是如果我们仔细观察,c字符在abd中不存在,那么abd可以直接移动到主串中c字符的后面再继续匹配:这样移动的步数变大了,匹配起来肯定更快了。

BM算法根据模式串的特定规律,这里面的特定规律有两种,一种是好后缀规则,一种是坏字符规则,初次看到这种规则的介绍后,心里嘀咕着这性能会好吗,后面才发现经典的BM算法做了不少优化,所以性能高。

下面分别介绍下好后缀规则(good suffix shift)和坏字符规则(bad character rule)。

1.1 BM坏字符规则首先在BM算法里面何谓好坏那,匹配上的,我们称为好,匹配不上的叫坏。

按照刚才说的,BM算法是倒着匹配字符串的,我们在倒着匹配字符串的过程中,当我们发现某个字符没法匹配的时候,我们把主串中这个没法匹配的字符称为坏字符。

我们发现在模式串中,字符c是不存在的,所以可以直接将模式字符串向后滑动3位继续匹配。

滑动后,我们继续匹配,发现主串中的字符a和模式串的d不匹配,这时候的情况和上一种不一样,因为主串中的坏字符a在模式串中存在,则后移动2位,让主串和模式串中的a对齐继续匹配。

那么每次后移多少位那,我们假设把匹配不到的坏字符的位置记作si,如果坏字符在模式串中存在,则坏字符在模式串中的位置记作xi,那么模式串后移为si-xi;如果坏字符在模式串中不存在,xi就为-1。

空间复杂度为o(1)的字符串匹配算法

空间复杂度为o(1)的字符串匹配算法

空间复杂度为o(1)的字符串匹配算法字符串匹配算法指的是在一个较大的字符串中查找是否存在另一个较小的字符串,该算法需要分析模式串(即要查找的字符串)和文本串(即被查找的字符串)的关系,从而确定是否匹配。

在许多实际应用中,需要处理大规模的文本数据,因此,空间复杂度为o(1)的字符串匹配算法成为了很有局限性但仍然很重要的算法之一,本文将详细介绍这一算法。

一、朴素算法在介绍空间复杂度为o(1)的字符串匹配算法之前,先介绍一下朴素算法。

朴素算法,也称暴力算法,是最为简单的字符串匹配算法,它的思想就是从文本串的第一个字符开始,不断地与模式串进行比较,直到匹配成功或者失败。

其时间复杂度为O(nm),其中n和m分别代表文本串和模式串的长度。

因为朴素算法仅仅使用了常数级别的空间,所以其空间复杂度为O(1)。

二、KMP算法KMP算法是一种常见的字符串匹配算法,它采用动态规划的思想,在处理匹配失败的情况时,利用已经匹配成功的信息来避免重复匹配。

KMP算法的总时间复杂度为O(n),其中n代表文本串的长度,所以它比朴素算法要快得多。

KMP算法的空间复杂度为O(m),其中m代表模式串的长度,因为需要额外维护一个长度为m的next数组。

KMP算法能够快速地找到模式串在文本串中的出现位置,但是在实际应用中,需要使用空间却很有限。

因此,需要一种空间复杂度为o(1)的字符串匹配算法,以满足实际需求。

三、Rabin-Karp算法Rabin-Karp算法是一种基于哈希的字符串匹配算法,它的思想是通过哈希函数将文本串和模式串转换为数字,在比较时,可通过比较hash值来判断它们是否相等。

Rabin-Karp算法的时间复杂度为O(n),其中n代表文本串的长度,但是它的空间复杂度为O(1)。

Rabin-Karp算法的实现流程如下:1. 计算模式串的hash值2. 对于文本串中长度为m的所有子串,计算其hash 值并与模式串的hash值进行比较3. 如果两个hash值相等,则继续比较每个字符是否相等,如果相等,则匹配成功,如果不相等,则继续比较下一个子串4. 如果遍历完了所有子串,仍然没有找到匹配的子串,则匹配失败Rabin-Karp算法的优点是它的空间复杂度只有O(1),但是它的缺点是如果出现hash冲突,则可能会导致误判。

bf,bm,kmp算法代码,实验报告

bf,bm,kmp算法代码,实验报告

bf,bm,kmp算法代码,实验报告BF算法、KMP算法、BM算法昆明理工大学信息工程与自动化学院学生实验报告(2010 —2011 学年第一学期)课程名称:算法分析与设计开课实验室:计算中心310 2010 年11 月12 日一、实验内容和目的1、深刻理解并掌握蛮力算法的设计思想;2、提高应用蛮力算法设计算法的技能;3、理解这样一个观点:用蛮力法设计的算法,一般来说,经过适度的努力后,都可以对算法的第一个版本进行一定程度的改良,改进其时间性能。

二、实验原理及基本技术路线图(方框原理图)串匹配问题——给定两个串S=“s1s2?sn”和T=“t1t2?tm”,在主串S中查找子串T的过程称为串匹配,也称模式匹配。

串匹配问题属于易解问题。

串匹配问题的特征:(1)算法的一次执行时间不容忽视:问题规模n 很大,常常需要在大量信息中进行匹配;(2)算法改进所取得的积累效益不容忽视:串匹配操作经常被调用,执行频率高。

BF算法:基本思想:从主串S的第一个字符开始和模式T的第一个字符进行比较,若相等,则继续比较两者的后续字符;若不相等,则从主串S的第二个字符开始和模式T的第一个字符进行比较,重复上述过程,若T中的字符全部比较完毕,则说明本趟匹配成功;若最后一轮匹配的起始位置是n-m,则主串S中剩下的字符不足够匹配整个模式T,匹配失败。

这个算法称为朴素的模式匹配算法,简称BF算法。

KMP算法:1. 在串S和串T中分别设比较的起始下标i和j;2. 循环直到S中所剩字符长度小于T的长度或T中所有字符均比较完毕2.1 如果S[i]=T[j],则继续比较S和T的下一个字符;否则2.2 将j向右滑动到next[j]位置,即j=next[j];2.3 如果j=0,则将i和j 分别加1,准备下一趟比较;2.4 如果T中所有字符均比较完毕,则返回匹配的起始下标;否则返回0;BM算法:BM算法与KMP算法的主要区别是匹配操作的方向不同。

BMY、KMP、BM、BMHS算法性能比较

BMY、KMP、BM、BMHS算法性能比较
int i, pos = 0;
for (pos = 1; pos <= len_s - len_d + 1;) {
num_bmhs++; for (i=pos+len_d-2; i>=pos-1 ; i--) {
if (src[i] == des[i-pos+1]) {
bidui_bmhs++; } else if (src[i] != des[i-pos+1]) {
void BuildGoodS(const char *pattern, size_t pattern_length, unsigned int* goods) {
unsigned int i, j, c; for(i = 0; i < pattern_length - 1; ++i) {
goods[i] = pattern_length; }
num_kmp++; //模式串和文本串从前向后匹配 while(i == -1 || s[j] == p[i])
{ i++; j++; bidui_kmp++;
if(i == plen) break;
} bidui_kmp++; //找到匹配的模式串 if(i == plen) {
res.push_back(j-i); j += 1; i = 0; match_kmp++; } //出现失配的情况 else {
for (int i=0; i<plen; i++) alphabet[des[i]] = plen - i - 1;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
iii.如果在P中条件i和ii都不满足时(即没有符合条件的子串匹配,也没有最长前缀匹配),此时直接将模式串P向后移动m,m为模式串P的长度。
移动规则我理解应该是上面的5条,坏字符规则2条,好后缀规则3条。对于好后缀规则1,我想再用图解释一下:
3
2
1
t
上图指的是模式串P,假设下表从1开始,由图可知,P[1…3]、P[7…9]、P[13…15]、P[20…22]和后缀P[26…28]相匹配,但我们首先要选个最大,首先考虑的是P[20…22]子串,但因为P[19]和P[25]相同,所以不符合条件。则P[13…15]符合条件。(这里有个需要注意的地方,就是如果假设只有P[1…3]和后缀P[26…28]相匹配,此时需要判断P[25]和P[0],因为P[0]是不存在的,所以认为P[25]和P[0]是不等的,即P[1…3]满足条件)
这个表看似神奇,实际从原理上讲并不复杂,对于模式串而言,其前缀字符串,有可能也是模式串中的非前缀子串,这个问题我称之为前缀包含问题。以模式串abcabcacab为例,其前缀abca,正好也是模式串的一个子串abc(abca)cab,所以当目标串与模式串执行匹配的过程中,如果直到第8个字符才匹配失败,同时也意味着目标串当前字符之前的4个字符,与模式串的前4个字符是相同的,所以当模式串向后移动的时候,可以直接将模式串的第5个字符与当前字符对齐,执行比较,这样就实现了模式串一次性向前跳跃多个字符。这里只是一个模式串移动的思想。
i.如果字符x在模式P中没有出现,那么含有字符x的m个文本显然不可能与P匹配成功,直接全部跳过该区域即可(即将模式串的第一个字符与X下一个位置字符比较)。
ii.如果x在模式P中出现,则将该坏字符x与模式串中从右向左最早出现字符x的位置对应。
所谓的坏字符移动规则,就是一个表,根据原论文,命名为delta1。其以目标串输入字符集的所有字符作为索引,每个输入字符c对应着一个值,表示如果目标串的当前位置字符c与模式串匹配失败,那么目标串当前位置应该可以向前滑动的步数(注意这里说的是“目标串当前位置”的滑动)。
如果P[j] !=P[f(j)],next[j] = f(j);
如果P[j] =P[f(j)],next[j] = next[f(j)];
当要求f(9)时,f(8)和next[8]已经可以得到,此时我们可以考察P[next[8]],根据前面对于next值的计算方式,我们知道P[8] !=P[next[8]]。我们的目的是要找到P[9]的包含前缀,而P[8] !=P[5],P[1...5]!=P[4...8]。我们继续考察P[next[5]]。如果P[8] =P[next[5]],假设next[5] =2,说明P[1] =P[4]= P[7],且P[2] =P[8],此时对于P[9]而言,就有P[1...2]=P[7...8],我们就找到了f(9) =3。这里我们考察的是P[next[j]],而不是P[f(j)],这是因为对于next[]而言,P[j] !=P[next[j]],而对于f()而言,P[j]与P[f(j)]不一定不相等,而我们的目的就是要在P[j] !=P[f(j)]的情况下,解决f(j+1)的问题,所以使用next[j]向前回溯,是正确的。
网上对于BM算法思想的分析真的是各种理解,其中有两篇博客我觉得写的比较清楚,值得参考学习,在文章结尾给出链接。
针对坏字符和好后缀,给出了两个表,坏字符表和好后缀表,匹配过程中的移动要借助着两个表,对于这两个表我给出自己的理解。
1.坏字符规则
在BM算法从右向左扫描的过程中,若发现某个字符x(这个字符X是指目标串中的字符)不匹配,则按如下两种情况讨论:
3.关于模式串的移动
很多文章中都说匹配过程中对模式串进行移动,但这里很多时候说的都不清楚,或者我感觉前后是矛盾的。
有模式串P和目标串T,发现不匹配,
根据下面说明的5条移动规则可知,移动后结果如下:
针对模式串P而言,模式串向后移动的距离为3,对于目标串当前位置而言,向后移动的距离确实6。而针对这个问题,很多文章没有给出详细的说明,这两个概念混淆不清,一会说模式串移动,其实给出的值却是针对目标串当前位置的。
说下如何根据next[i]的值进行移动。如果目标字符串匹配失败字符对应的是模式串中第i个字符,则将模式串向后移动i–next[i]后继续进行匹配。
BM算法
而BM算法在移动模式串的时候是从左到右,而进行比较的时候是从右到左的,基本框架是:
j = 0;
while (j <= strlen(T) - strlen(P)) {
其实利用之前的结果,我们还可以得到更多的信息。还是以P[8]为例。f(8) = 5,P[1...4]=P[4...7],此时我们需要关注P[8],如果P[8] !=P[5],那么在匹配算法如果匹配到P[8]才失败,此时就可以将输入字符T[n]与P[f(8)] =P[5]对齐,再向后依次执行匹配,所以此时的next[8] = f(8)。而如果P[8] =P[5],那么P[1...5]=P[4...8],如果T[n]与P[8]匹配失败,那么同时也意味着T[n-5...n]!=P[4...8],那么将T[n]与P[5]对齐,T[n-5...n]也必然不等于P[1...5],此时我们需要关注f(5) = 2,这意味着P[1] =P[4],因为P[1...4]=P[4...7],所以P[4]=P[7]=P[1],此时我们再来比较P[8]与P[2],如果P[8] !=P[2],就可以将T[n]与P[2],然后比较二者是否相等,此时next[8] = next[5] = f(2)。如果P[8] =P[2],那么还需要考察P[f(2)],直到回溯到模式串头部为止。下面给出根据f(j)值求next[j]的递推公式:
上图可以很好的说明坏字符和好后缀,即后缀匹配过程中,已匹配的部分为好后缀,第一个不匹配字符为坏字符。很多理解对于坏字符和好后缀就停留在这里了,其实我觉得这里还有一个很重要的概念,就是坏字符和好后缀是相对于谁而言的(是针对T还是P的呢)。从我个人的理解(不一定是正确的)看,坏字符是相对于目标串T的,也就是指的上图中的b,而不是模式串中的c。好后缀是相对于模式串P的,也就是指的上图中的下面的aba。至于为什么这样理解,我觉得这样对于后面理解模式串的移动是有帮助的。
如何以较小的代价计算KMP算法中所用到的跳转表next,是算法的核心问题。这里我们引入一个概念f(j),其含义是,对于模式串的第j个字符P[j],f(j)是所有满足使P[1...k-1] =P[j-(k-1)...j - 1](k < j)成立的k的最大值。还是以模式串abcabcacab(下标从1开始)为例,当处理到P[8] = 'c'时,我们想找到'c'前面的k-1个字符,使得P[1...k-1] =P[8-(k-1)...7],这里我们可以使用一个笨法,让k-1从1到6递增,然后依次比较,直到找到最大值的k为止。但是这样的方法比较低效,而且没有充分利用到之前的计算结果。在我们处理P[8] = 'c'之前,P[7] = 'a'的最大前缀包含问题已经解决,f(7) = 4,也就是说,P[4...6] =P[1...3],此时我们可以比较P[7]与P[4],如果P[4]=P[7],对于P[8]而言,说明P[1...4]=P[4...7],此时,f(8) = f(7) + 1 = 5。再以P[9]为例,f(8) = 5,P[1...4]=P[4...7],但是P[8] !=P[5],所以P[1...5]!=P[4...8],此时无法利用f(8)的值直接计算出f(9)。
2.好后缀移动规则
好后缀移动规则是BM算法的核心,这里分三种情况讨论:
i.如果在P中位置t处已匹配部分P'在P中的某位置t'也出现,且位置t'的前一个字符与位置t的前一个字符不相同,则将P右移使t'对应t方才的所在的位置。如果同时有多个t'出现时,选择最大的那个t'。
ii.如果在P中任何位置已匹配部分P'都没有再出现,则找到与P'的后缀P''相同的P的最长前缀x(这里是前缀不是子串),向右移动P,使x对应方才P''后缀所在的位置。
现在,我们来总结一下next[j]和f(j)的关系,next[j]是所有满足P[1...k - 1] =P[(j - (k - 1))...j -1](k < j),且P[k] !=P[j]的k中,k的最大值。而f(j)是满足P[1...k - 1] =P[(j - (k - 1))...j -1](k < j)的k中,k的最大值。还是以上例的模式来说,对于第7个元素,其f(j) = 4,说明P[7]的前3个字符与模式的前缀3相同,但是由于P[7] =P[4],所以next[7] != 4。
首先有几个概念要先说清楚,我发现很多文章里面完全没有说或者只说了部分。
1.目标串和模式串
目标串是我们需要在其中查找匹配的字符串,一般用T(T)表示,模式串是给定的需要匹配的字符串,一般用P(P)表示。EX:T=abababaabab,P=acaba,我们的任务是判断在T中是否有和P相匹配的字符串。
2.坏字符和好后缀
坏字符表的定义为,对于输入字符集合中的字符c,如果c不在模式串中,则delta1[c]= patlen(模式串的长度),如果c在模式串中,则delta1[c]=j-i,其中,j是模式串最末元素的索引值,i是字符c在模式串中最右出现的位置。用数学公式表示,设m为模式串P的长度,max(x)为字符x在P中最右位置。
那为什么要分清这两个概念呢,其实用哪个都是一样的,关键是在匹配过程中概念上要统一。在很多的匹配情况中,好后缀和坏字符是同时出现的,这个时候就要运用坏字符规则和好后缀规则,从中找一个值大的,进行更大的移动。如果坏字符规则得到的数值是针对模式串的,好后缀规则得到的数值是针对目标串当前位置的话,那么算法将得不到正确解。下面关于BM算法的移动讨论都是针对目标串当前位置的。
相关文档
最新文档