KMP算法的介绍
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)
kmp
2 KMP算法:KMP算法是由D.E.Knuth(克努特),J.H.Morris(莫里斯),V.R.Pratt(普拉特)等人共同提出的,该算法主要消除了主串指针(i指针)的回溯,利用已经得到的部分匹配结果将模式串右滑尽可能远的一段距离再继续比较,从而使算法效率有某种程度的提高,O(n+m)。
先从例子入手(p82):按Brute-Force算法i=i-j+2=2-2+2=2,j=1按Brute-Force算法i=i-j+2=2-1+2=3,j=1按Brute-Force算法i=i-j+2=8-6+2=4,j=1,但从已匹配的情况看,模式串在t[6]即“c”前的字符都是匹配的,再看已匹配的串“abaab”,t[1]t[2]与t[4]t[5]相同,那么,因为t[4]t[5]与原串s[6]s[7]匹配,所以t[1]t[2]必然与原串s[6]s[7]匹配,因此说t[3]可以直接与s[8]匹配,按KMP 算法i=8,j=3匹配成功。
从上例看出在匹配不成功时,主串指针i不动,j指针也不回到第一个位置,而是回到一个恰当的位置,如果这时让j指针回到第一个位置,就可能错过有效的匹配,所以在主串指针i不动的前提下,j指针回到哪个位置是问题的关键,既不能将j右移太大,而错过有效的匹配,另一方面,又要利用成功的匹配,将j右移尽可能地大,而提高匹配的效率,因此问题的关键是寻找模式串自身的规律。
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////。
和直接比较若不满足和直接比较所以:满足:,设1i i 12112111112121s ),2(;s )1(""")"2(""")"1(""""t t j k t t t t t t t t s s t t t t s s s s k j k j k j k j i j i m n <<====-+-+----+-////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////设s=” s 1 s 2 ... s n ”, t=” t 1 t 2 ... t m ”,在匹配过程中,当s i ≠ t j (1≤i ≤n-m+1,1≤j ≤m)时,存在(前面的j-1个字符已匹配):” s i-j+1 ... s i-1 ” =” t 1 t 2 ... t j-1 ” (1) 若模式中存在可互相重叠的最长的真子串,满足: ” t 1 t 2 ... t k-1 ”=”t j-k+1 t j-k+2 ... t j-1 ” (2) 其中真子串最短可以是t 1 ,即 t 1。
实验04:串应用KMP算法PPT课件
在生物信息学中的应用
在生物信息学中,KMP算法被广泛应用于基因序列的比对和拼接,以及蛋白质序列 的匹配和比对。
通过构建基因序列或蛋白质序列的索引表,KMP算法可以在O(n+m)的时间复杂度 内完成序列的比对和拼接,提高了比对和拼接的准确性和效率。
KMP算法在生物信息学中的应用有助于深入了解基因和蛋白质的结构和功能,为生 物医学研究和疾病诊断提供了有力支持。
06 实验总结与展望
KMP算法的优缺点
优点
高效:KMP算法在匹配失败时能跳过 尽可能多的字符,减少比较次数,从
而提高匹配效率。
适用范围广:KMP算法适用于各种模 式串匹配问题,不受模式串长度的限 制。
缺点
计算量大:KMP算法需要计算和存储 部分匹配表,对于较长的模式串,计 算量较大。
不适合处理大量数据:KMP算法在处 理大量数据时可能会占用较多内存, 导致性能下降。
匹配失败的处理
当模式串中的某个字符与主串中的对应字符不匹配时,模式串向右 滑动,与主串的下一个字符重新对齐,继续比较
next[ j]表示当模式串中第j个字符与主 串中的对应字符不匹配时,模式串需 要向右滑动的位置。
next数组的构建
next数组的作用
在匹配过程中,通过next数组可以快 速确定模式串需要滑动到哪个位置, 从而提高了匹配效率。
通过已知的next值,递推计算出next 数组中其他位置的值。
KMP算法的时间复杂度
01
02
03
04
时间复杂度分析
KMP算法的时间复杂度取决 于模式串在主串中出现的次数 以及每次匹配所花费的时间。
最佳情况
当模式串在主串中连续出现时 ,KMP算法的时间复杂度为
KMP算法计算next值和nextVal值
KMP算法计算next值和nextVal值
KMP算法:
给定⼀个主串S及⼀个模式串P,判断模式串是否为主串的⼦串;若是,返回匹配的第⼀个元素的位置(序号从1开始),否则返回0;这⾥先不写算法,仅仅计算next和nextVal值
那么计算时只⽤到⼦串,也就是模式串
这⾥模式串为:abaabcac
第⼀步将模式串写上序号,我们这⾥从1开始(有的从0开始,建议充1开始)
然后计算出maxL值,列出从第⼀个开始的⼦串,找出相等的前缀和后缀的个数
如果2>看不懂的话,看3>,
2>计算maxL值
所以maxL值
如果这个看不懂的话,看下⾯的3>
3>,如果2>看懂了这个就不⽤看了
依次类推4>计算next值
接下来将maxL复制⼀⾏,去掉最后⼀个数,在开头添加⼀个-1,向右平移⼀个格,然后每个值在加1的到next值
5>计算nextVal值,⾸先将第⼀个为0,然后看next和maxL是否相等(先计算不相等的)
当next和maxL不相等时,将next的值填⼊
当next和maxL相等时,填⼊对应序号为next值得nextVal值
所以整个nextVal值为:。
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]。
KMP算法(改进的模式匹配算法)——next函数
KMP算法(改进的模式匹配算法)——next函数KMP算法简介KMP算法是在基础的模式匹配算法的基础上进⾏改进得到的算法,改进之处在于:每当匹配过程中出现相⽐较的字符不相等时,不需要回退主串的字符位置指针,⽽是利⽤已经得到的部分匹配结果将模式串向右“滑动”尽可能远的距离,再继续进⾏⽐较。
在KMP算法中,依据模式串的next函数值实现字串的滑动,本随笔介绍next函数值如何求解。
next[ j ]求解将 j-1 对应的串与next[ j-1 ]对应的串进⾏⽐较,若相等,则next[ j ]=next[ j-1 ]+1;若不相等,则将 j-1 对应的串与next[ next[ j-1 ]]对应的串进⾏⽐较,⼀直重复直到相等,若都不相等则为其他情况题1在字符串的KMP模式匹配算法中,需先求解模式串的函数值,期定义如下式所⽰,j表⽰模式串中字符的序号(从1开始)。
若模式串p 为“abaac”,则其next函数值为()。
解:j=1,由式⼦得出next[1]=0;j=2,由式⼦可知1<k<2,不存在k,所以为其他情况即next[2]=1;j=3,j-1=2 对应的串为b,next[2]=1,对应的串为a,b≠a,那么将与next[next[2]]=0对应的串进⾏⽐较,0没有对应的串,所以为其他情况,也即next[3]=1;j=4,j-1=3 对应的串为a,next[3]=1,对应的串为a,a=a,所以next[4]=next[3]+1=2;j=5,j-1=4 对应的串为a,next[4]=2,对应的串为b,a≠b,那么将与next[next[4]]=1对应的串进⾏⽐较,1对应的串为a,a=a,所以next[5]=next[2]+1=2;综上,next函数值为 01122。
题2在字符串的KMP模式匹配算法中,需先求解模式串的函数值,期定义如下式所⽰,j表⽰模式串中字符的序号(从1开始)。
若模式串p为“tttfttt”,则其next函数值为()。
KMP算法详解
KMP算法详解KMP 算法详解KMP 算法是⼀个⼗分⾼效的字符串查找算法,⽬的是在⼀个字符串 s 中,查询 s 是否包含⼦字符串 p,若包含,则返回 p 在 s 中起点的下标。
KMP 算法全称为 Knuth-Morris-Pratt 算法,由 Knuth 和 Pratt 在1974年构思,同年 Morris 也独⽴地设计出该算法,最终由三⼈于1977年联合发表。
举⼀个简单的例⼦,在字符串 s = ababcabababca 中查找⼦字符串 p = abababca,如果暴⼒查找,我们会遍历 s 中的每⼀个字符,若 s[i] = p[0],则向后查询p.length() 位是否都相等。
这种朴素的暴⼒的算法复杂度为O(m×n),其中m和n分别是 p 和 s 的长度。
KMP 算法可以⽅便地简化这⼀查询的时间复杂度,达到O(m+n)。
1. PMT 序列PMT 序列是 KMP 算法的核⼼,即 Partial Match Table(部分匹配表)。
举个例⼦:char a b a b a b c aindex01234567PMT00123401PMT 的值是字符串的前缀集合与后缀集合的交集中最长元素的长度。
PMT[0] = 0: 字符串 a 既没有前缀,也没有后缀;PMT[1] = 0: 字符串 ab 前缀集合为 {a},后缀集合为 {b},没有交集;PMT[2] = 1: 字符串 aba 前缀集合为 {a, ab},后缀集合为 {ba, a},交集为 {a},交集元素的最长长度为1;PMT[3] = 2: 字符串 abab 前缀集合为 {a, ab, aba},后缀集合为 {bab, ab, b},交集为 {ab},交集元素的最长长度为2;…… 以此类推。
2. 算法主体现在我们已经知道了 PMT 序列的含义,那么假设在 PMT 序列已经给定的情况下,如何加速字符串匹配算法?tar 存储 s 的下标,从 0 开始,若 tar > s.length() - 1,代表匹配失败;pos 存储 p 的下标,从 0 开始,若 s[tar] != p[pos],则 pos ⾛到下⼀个可能匹配的位置。
数据结构kmp算法例题
数据结构kmp算法例题KMP算法(Knuth-Morris-Pratt算法)是一种用于在一个主文本字符串S内查找一个模式字符串P的高效算法。
它利用了模式字符串内部的信息来避免在主字符串中不必要的回溯。
这种算法的关键在于构建一个部分匹配表,用于指示模式字符串中出现不匹配时的下一步匹配位置。
让我们来看一个KMP算法的例题:假设我们有一个主文本字符串S为,"ABC ABCDAB ABCDABCDABDE",模式字符串P为,"ABCDABD"。
我们要在主文本字符串S中查找模式字符串P的出现位置。
首先,我们需要构建模式字符串P的部分匹配表。
部分匹配表是一个数组,用于存储模式字符串中每个位置的最长相同前缀后缀的长度。
模式字符串P,"ABCDABD"部分匹配表:A B C D A B D.0 0 0 0 1 2 0。
接下来,我们使用KMP算法来在主文本字符串S中查找模式字符串P的出现位置。
算法的关键步骤如下:1. 初始化两个指针i和j,分别指向主文本字符串S和模式字符串P的起始位置。
2. 逐个比较S[i]和P[j],如果相等,则继续比较下一个字符;如果不相等,则根据部分匹配表调整j的位置。
3. 如果j达到了模式字符串P的末尾,则说明找到了一个匹配,记录匹配位置,并根据部分匹配表调整j的位置。
4. 继续比较直到遍历完主文本字符串S。
根据上述步骤,我们可以在主文本字符串S中找到模式字符串P的所有出现位置。
总结来说,KMP算法通过构建部分匹配表和利用匹配失败时的信息来避免不必要的回溯,从而实现了高效的字符串匹配。
希望这个例题能帮助你更好地理解KMP算法的原理和应用。
kmp 压力
KMP算法简介什么是KMP算法KMP算法(Knuth-Morris-Pratt算法)是一种用于字符串匹配的算法,用于在一个主串中查找一个模式串的出现位置。
它的特点是在匹配失败时,不回溯主串的指针,而是通过利用已经匹配过的信息,将模式串尽量地向后移动,从而提高匹配效率。
KMP算法的原理KMP算法的核心思想是利用模式串自身的特点,通过预处理模式串,构建一个部分匹配表(Partial Match Table),从而在匹配过程中可以根据已匹配的信息来决定下一步的匹配位置。
部分匹配表部分匹配表是一个与模式串对应的数组,用于存储模式串在每个位置上的最长相同前缀后缀的长度。
例如,对于模式串”ABCDABD”,其部分匹配表为:位置部分匹配值0 01 02 03 04 15 26 0KMP算法的匹配过程KMP算法的匹配过程可以简述为以下几个步骤:1.预处理模式串,构建部分匹配表;2.在主串中从左到右逐个字符进行匹配;3.如果当前字符匹配成功,则继续比较下一个字符;4.如果当前字符匹配失败,则根据部分匹配表,将模式串向右移动一定的距离,再次进行匹配;5.重复步骤3和4,直到模式串匹配完毕或者主串匹配完毕。
KMP算法的优势相较于朴素的字符串匹配算法,KMP算法具有以下优势:1.减少了不必要的字符比较次数,提高了匹配效率;2.通过预处理模式串,可以在匹配过程中根据已匹配的信息决定下一步的匹配位置,避免了回溯主串的指针。
KMP算法的应用KMP算法在字符串匹配中有着广泛的应用,例如:1.字符串查找:在一个文本中查找一个子串的出现位置;2.字符串替换:将一个文本中的某个子串替换为另一个字符串;3.DNA序列匹配:在生物信息学中,用于比对DNA序列的相似性。
KMP算法的压力测试为了验证KMP算法的效率和稳定性,我们进行了一系列的压力测试。
测试环境•操作系统:Windows 10•处理器:****************************•内存:16GB测试方法我们使用不同长度的主串和模式串进行匹配,记录下KMP算法的执行时间,并与朴素的字符串匹配算法进行对比。
KMP模式匹配算法
KMP模式匹配算法KMP算法是一种字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。
该算法的核心思想是通过预处理模式串,构建一个部分匹配表,从而在匹配过程中尽量减少不必要的比较。
KMP算法的实现步骤如下:1.构建部分匹配表部分匹配表是一个数组,记录了模式串中每个位置的最长相等前后缀长度。
从模式串的第二个字符开始,依次计算每个位置的最长相等前后缀长度。
具体算法如下:-初始化部分匹配表的第一个位置为0,第二个位置为1- 从第三个位置开始,假设当前位置为i,则先找到i - 1位置的最长相等前后缀长度记为len,然后比较模式串中i位置的字符和模式串中len位置的字符是否相等。
- 如果相等,则i位置的最长相等前后缀长度为len + 1- 如果不相等,则继续判断len的最长相等前后缀长度,直到len为0或者找到相等的字符为止。
2.开始匹配在主串中从前往后依次查找模式串的出现位置。
设置两个指针i和j,分别指向主串和模式串的当前位置。
具体算法如下:-当主串和模式串的当前字符相等时,继续比较下一个字符,即i和j分别向后移动一个位置。
-当主串和模式串的当前字符不相等时,根据部分匹配表确定模式串指针j的下一个位置,即找到模式串中与主串当前字符相等的位置。
如果找到了相等的位置,则将j移动到相等位置的下一个位置,即j=部分匹配表[j];如果没有找到相等的位置,则将i移动到下一个位置,即i=i+13.检查匹配结果如果模式串指针j移动到了模式串的末尾,则说明匹配成功,返回主串中模式串的起始位置;如果主串指针i移动到了主串的末尾,则说明匹配失败,没有找到模式串。
KMP算法的时间复杂度为O(m+n),其中m为主串的长度,n为模式串的长度。
通过预处理模式串,KMP算法避免了在匹配过程中重复比较已经匹配过的字符,提高了匹配的效率。
总结:KMP算法通过构建部分匹配表,实现了在字符串匹配过程中快速定位模式串的位置,减少了不必要的比较操作。
kmp next算法
kmp next算法KMP算法(Knuth-Morris-Pratt Algorithm)是一种字符串匹配算法,它的核心思想是利用已经得到的匹配结果,尽量减少字符的比较次数,提高匹配效率。
本文将详细介绍KMP算法的原理、实现方法以及应用场景。
一、KMP算法的原理KMP算法的核心是构建next数组,用于指导匹配过程中的回溯操作。
next数组的定义是:对于模式串中的每个字符,记录它前面的子串中相同前缀和后缀的最大长度。
next数组的长度等于模式串的长度。
具体来说,KMP算法的匹配过程如下:1. 初始化主串指针i和模式串指针j为0。
2. 逐个比较主串和模式串对应位置的字符:- 若主串和模式串的字符相等,i和j同时后移一位。
- 若主串和模式串的字符不相等,根据next数组的值,将模式串指针j回溯到合适的位置,继续匹配。
二、KMP算法的实现KMP算法的实现可以分为两个步骤:构建next数组和利用next数组进行匹配。
1. 构建next数组:- 首先,next[0]赋值为-1,next[1]赋值为0。
- 然后,从第2个位置开始依次计算next[i],根据前一个位置的next值和模式串的字符进行判断:- 若前一个位置的next值为-1或模式串的字符与前一个位置的字符相等,则next[i] = next[i-1] + 1。
- 若前一个位置的next值不为-1且模式串的字符与前一个位置的字符不相等,则通过next数组的回溯操作,将模式串指针j回溯到合适的位置,继续判断。
2. 利用next数组进行匹配:- 在匹配过程中,主串指针i和模式串指针j会同时后移:- 若主串和模式串的字符相等,i和j同时后移一位。
- 若主串和模式串的字符不相等,则根据next数组的值,将模式串指针j回溯到合适的位置,继续匹配。
三、KMP算法的应用场景KMP算法在字符串匹配中有广泛的应用,特别是在大规模文本中的模式匹配问题上具有明显的优势。
以下是KMP算法的几个应用场景:1. 子串匹配:判断一个字符串是否是另一个字符串的子串。
KMP算法
KMP算法KMP算法是一种用于字符串匹配的快速算法,全称为Knuth-Morris-Pratt算法,是由Donald Knuth、Vaughan Pratt和James Morris在1977年共同提出的。
该算法的核心思想是通过利用已经匹配过的部分来避免不必要的字符比较,从而提高匹配效率。
1.暴力匹配算法在介绍KMP算法之前,我们先来了解一下暴力匹配算法。
暴力匹配算法,又称为朴素匹配算法,是最基本的匹配方法,它的思想就是从主串的第一个字符开始,逐个比较主串和模式串的字符,直到匹配成功或者主串和模式串的所有字符都比较完毕。
具体算法如下:```暴力匹配(主串S,模式串P):i=0j=0n = length(S)m = length(P)while i < n and j < m:if S[i] == P[j]: // 匹配成功,继续比较下一个字符i++else: // 匹配失败,模式串向后移动一位i=i-j+1j=0if j == m: // 匹配成功return i - jelse: // 匹配失败return -1```暴力匹配算法的时间复杂度为O(n*m),其中n和m分别为主串和模式串的长度。
2.KMP算法的思想KMP算法的关键在于构建一个部分匹配表,通过这个表来确定模式串在匹配失败时应该移动的位置。
部分匹配表的定义如下:对于模式串P的前缀子串P[0:i],如果存在一个真前缀等于真后缀,则称其长度为i的真前缀的真后缀长度为部分匹配值。
假设有一个模式串P,我们定义一个部分匹配表next,其中next[i]表示在P[i]之前的子串(不包括P[i])中,有多大长度的相同前缀后缀。
例如,P="ABCDABD",则next[7]=2,因为在P[7]之前的子串中,"ABD"是长度为3的前缀,也是长度为3的后缀。
构建部分匹配表的算法如下:构建部分匹配表(P):m = length(P)next = [0] * m // 初始化部分匹配表j=0k=-1next[0] = -1while j < m - 1:if k == -1 or P[j] == P[k]: // P[j]表示后缀的单个字符,P[k]表示前缀的单个字符j++k++next[j] = kelse:k = next[k]```构建部分匹配表的时间复杂度为O(m),其中m为模式串的长度。
字符串匹配方法
字符串匹配方法引言:字符串匹配是计算机科学中一项重要的技术,它在文本处理、数据分析、搜索引擎等领域都有广泛的应用。
本文将介绍几种常见的字符串匹配方法,包括暴力匹配、KMP算法、Boyer-Moore算法和正则表达式。
一、暴力匹配算法暴力匹配算法,也称为朴素匹配算法,是最简单直观的字符串匹配方法。
它的思想是从待匹配文本的第一个字符开始,依次与模式串进行比较,若匹配失败则移动到下一个字符继续比较,直到找到匹配的子串或者遍历完整个文本。
该算法的时间复杂度为O(n*m),其中n为文本长度,m为模式串长度。
二、KMP算法KMP算法是一种高效的字符串匹配算法,它的核心思想是通过预处理模式串,构建一个部分匹配表(Next数组),以便在匹配过程中根据已匹配的前缀字符来确定下一次匹配的位置。
这样可以避免不必要的回溯,提高匹配效率。
KMP算法的时间复杂度为O(n+m),其中n为文本长度,m为模式串长度。
三、Boyer-Moore算法Boyer-Moore算法是一种基于比较字符的右移策略的字符串匹配算法。
它的主要思想是从模式串的末尾开始与待匹配文本比较,若匹配失败则根据预先计算好的字符移动表来决定模式串的右移位数。
这样可以根据比较结果快速确定下一次比较的位置,从而提高匹配效率。
Boyer-Moore算法的时间复杂度为O(n/m),其中n为文本长度,m为模式串长度。
四、正则表达式正则表达式是一种强大的字符串匹配工具,它通过一种特定的语法规则来描述字符串的模式,并通过匹配模式来判断字符串是否符合要求。
正则表达式可以实现复杂的匹配功能,包括字符匹配、重复匹配、分组匹配等。
在文本处理、数据清洗、搜索引擎等领域都有广泛的应用。
结论:字符串匹配是计算机科学中一项重要的技术,不同的匹配方法适用于不同的应用场景。
暴力匹配算法简单直观,适用于模式串较短的情况;KMP算法通过预处理模式串,提高匹配效率;Boyer-Moore算法通过右移策略,减少不必要的比较次数;正则表达式可以实现复杂的匹配功能。
kmp百度百科
kmp算法[编辑本段]kmp算法-概述一种改进的字符串匹配算法,由 D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。
[编辑本段]kmp算法-学习介绍完全掌握KMP算法思想学过数据结构的人,都对KMP算法印象颇深。
尤其是新手,更是难以理解其涵义,搞得一头雾水。
今天我们就来面对它,不将它彻底搞懂,誓不罢休。
如今,大伙基本上都用严蔚敏老师的书,那我就以此来讲解KMP 算法。
(小弟正在备战考研,为了节省时间,很多课本上的话我都在此省略了,以后一定补上。
)严老的《数据结构》79页讲了基本的匹配方法,这是基础。
先把这个搞懂了。
80页在讲KMP算法的开始先举了个例子,让我们对KMP的基本思想有了最初的认识。
目的在于指出“由此,在整个匹配的过程中,i指针没有回溯,”。
我们继续往下看:现在讨论一般情况。
假设主串:s: ‘s(1) s(2) s(3) ……s(n)’; 模式串:p: ‘p(1) p(2) p(3)…..p(m)’把课本上的这一段看完后,继续现在我们假设主串第i个字符与模式串的第j(j<=m)个字符‘失配’后,主串第i个字符与模式串的第k(k<j)个字符继续比较此时,s(i)≠p(j), 有主串:S(1)……s(i-j+1)……s(i-1) s(i) ………….|| (相配) || ≠(失配)匹配串:P(1) ……. p(j-1) p(j)由此,我们得到关系式‘p(1) p(2) p(3)…..p(j-1)’= ’s(i-j+1)……s(i-1)’由于s(i)≠p(j),接下来s(i)将与p(k)继续比较,则模式串中的前(k-1)个字符的子串必须满足下列关系式,并且不可能存在k’>k 满足下列关系式:(k<j),‘p(1) p(2) p(3)…..p(k-1)’= ’s(i-k+1)s(i-k+2)……s(i-1)’即:主串:S(1)……s(i-k +1) s(i-k +2) ……s(i-1) s(i) ………….|| (相配) || || ?(有待比较)匹配串:P(1) p(2) ……p(k-1) p(k)现在我们把前面总结的关系综合一下有:S(1)…s(i-j +1)…s(i-k +1) s(i-k +2) ……s(i-1) s(i) ……|| (相配) || || || ≠(失配)P(1) ……p(j-k+1) p(j-k+2) ….... p(j-1) p(j)|| (相配) || || ?(有待比较)P(1) p(2) ……. p(k-1) p(k)由上,我们得到关系:‘p(1) p(2) p(3)…..p(k-1)’= ’s(j-k+1)s(j-k+2)……s(j-1)’接下来看“反之,若模式串中存在满足式(4-4)。
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)。
KMP算法(推导方法及模板)
KMP算法(推导⽅法及模板)介绍克努斯-莫⾥斯-普拉特算法Knuth-Morris-Pratt(简称为KMP算法)可在⼀个主⽂本S内查找⼀个词W的出现位置。
此算法通过运⽤对这个词在不匹配时本⾝就包含⾜够的信息来确定下⼀个匹配将在哪⾥开始的发现,从⽽避免重新检查先前匹配的。
此算法可以在O(n+m)时间数量级上完成串的模式匹配操作,其改进在于:每当⼀趟匹配过程中出现字符⽐较不等时,不需回溯i的指针,⽽是利⽤已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的距离后,继续进⾏⽐较。
kmp的核⼼之处在于next数组,⽽为了⽅便理解,我先介绍KMP的思想KMP匹配当开始匹配时,如果匹配过程中产⽣“失配”时,指针i(原串的下标)不变,指针j(模式串的下标)退回到next[j] 所指⽰的位置上重新进⾏⽐较,并且当指针j退回⾄零时,指针i和指针j需同时加⼀。
即主串的第i个字符和模式的第⼀个字符不等时,应从主串的第i+1个字符起重新进⾏匹配。
简单来说,就是两个串匹配,如果当前字符相等就⽐较两个字符串的下⼀个字符,如果当前匹配不相等时,就让j(待匹配串的下标)回到next[j] 的位置,因为我们已经知道next数组的作⽤是利⽤已经得到的“部分匹配”的结果将模式向右“滑动”尽可能远的距离,如ababac与abac⽐较时i=4,j=4时不匹配,则利⽤next数组让j=2继续匹配⽽不⽤重新开始。
(⽬前先不⽤管next数组的值时如何得到的,只要明⽩它的作⽤即可,下⾯回介绍)所以我们可以写出kmp的代码int KMP(char str[],char pat[]){int lenstr=strlen(str);int lenpat=strlen(pat);int i=1,j=1;while(i<=lenstr){if(j==0 || str[i]==pat[j]) //匹配成功继续往后匹配++i,++j;elsej=next[j]; //否则根据next数组继续匹配if(j==lenpat) //说明匹配完成return 1;}return 0;}接下来就是关键的求next数组了next数组⾸先,next数组取决于模式串本⾝⽽与相匹配的主串⽆关,我们可以对其递推得到。
KMP算法详解(超级详细)
KMP算法详解(超级详细)KMP算法,全称为Knuth-Morris-Pratt算法,是一种用于字符串匹配的快速算法。
它的核心思想是在匹配过程中,当出现不匹配的情况时,利用已经匹配的字符信息,避免进行重复匹配,从而提高匹配效率。
首先,我们需要了解一个重要的概念,"部分匹配值"(partialmatch table),它指的是字符串的前缀和后缀的最长的共有元素的长度。
例如,在字符串"ABCDABD"中,它的部分匹配值是[0, 0, 0, 0, 1, 2, 0]。
接下来,我们来详细了解KMP算法的实现过程:1.首先,针对模式串(被查找的字符串)进行预处理,得到部分匹配表。
-定义两个指针,i和j,分别指向模式串的开头和当前字符。
-初始化部分匹配表,将第一个元素置为0。
-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。
-若匹配,则将部分匹配表的下一个元素置为当前指针位置的下一个元素的值加1,并同时将当前指针和i都自增1-若不匹配且i>0,则将i更新为部分匹配表的前一个元素的值。
-若不匹配且i=0,则将当前指针自增1-循环结束后,部分匹配表得到构建。
2.匹配过程:-定义两个指针,i和j,分别指向需要匹配的文本和模式串的开头。
-在循环中,不断地根据当前指针所指向的字符,判断是否匹配。
-若匹配,则将两个指针都自增1-若不匹配且j>0,则将j更新为部分匹配表的前一个元素的值。
-若不匹配且j=0,则将当前指针自增1-若模式串的指针j指向了最后一个字符,则说明匹配成功,返回匹配的位置。
-若循环结束仍未找到匹配的位置,则匹配失败。
总结一下,KMP算法可以分为两个步骤:预处理和匹配。
预处理的过程是构建部分匹配表,通过比较前缀和后缀的最长共有元素的长度,将这个长度记录在部分匹配表中。
匹配的过程是根据部分匹配表中的信息,来确定下一步的匹配位置,提高匹配的效率。
通过KMP算法,我们可以有效地解决字符串匹配问题,提高了匹配的效率。
kmp算法next计算方法
kmp算法next计算方法KMP算法是一种字符串匹配的经典算法,它的核心在于利用已经部分匹配的信息来减少匹配的次数,从而提高匹配的效率。
而在KMP算法中,next数组的计算是至关重要的一步,它可以帮助我们快速定位到模式串中与文本串不匹配的位置,从而避免不必要的匹配操作。
本文将详细介绍KMP算法中next数组的计算方法。
首先,我们需要了解next数组的含义。
在KMP算法中,next数组用于记录模式串中每个位置的最长公共前缀和最长公共后缀的长度。
具体来说,对于模式串P,其next数组的第i个位置的值next[i]表示P[0]到P[i]这个子串的最长公共前缀和最长公共后缀的长度。
这样,当P[i]与T[j]不匹配时,我们就可以利用next数组中的信息来将模式串P相对于文本串T右移若干位,从而减少匹配的次数。
接下来,我们来介绍next数组的计算方法。
假设模式串P的长度为m,则next数组的长度也为m。
我们首先将next[0]赋值为-1,next[1]赋值为0,这是因为长度为1的子串没有真正的前缀和后缀。
然后,我们使用两个指针i和j来遍历模式串P,其中i从2开始,j从0开始。
在计算next[i]的过程中,我们需要考虑P[i-1]和P[j]两个字符。
如果P[i-1]等于P[j],则说明P[0]到P[i-1]这个子串的最长公共前缀和最长公共后缀的长度是j+1,于是我们将next[i]赋值为j+1,然后将i和j分别加1。
如果P[i-1]不等于P[j],则我们需要将j更新为next[j],然后继续比较P[i-1]和P[j]两个字符,直到找到相等的字符或者j变为0为止。
重复以上步骤,直到计算出整个next数组为止。
这样,我们就得到了模式串P的next数组。
通过计算得到的next数组,我们可以在KMP算法中利用部分匹配的信息来快速移动模式串,从而提高匹配的效率。
因此,next数组的计算是KMP算法中非常重要的一步,它直接影响到算法的性能和效率。
KMP算法
KMP算法在传统的字符串匹配算法中,最常用的算法是朴素的模式匹配算法。
该算法的基本思想是:从主串的第一个字符开始,逐个字符地与模式串进行比较,如果发现不匹配的字符,则回溯到主串的下一个字符重新开始匹配。
这种算法的时间复杂度是O(m*n),其中m为主串的长度,n为模式串的长度。
在主串与模式串长度相等时,该算法的时间复杂度甚至会达到O(n^2)。
KMP算法的核心思想是利用模式串的信息,避免不必要的比较。
它通过预处理模式串,构建一个部分匹配表(prefix table),来提供匹配失败时的回溯位置。
这样,在匹配的过程中,只需要根据部分匹配表的内容来调整主串和模式串的位置即可。
这种优化使得KMP算法的时间复杂度降低到O(m+n)。
具体来说,KMP算法在预处理模式串时,对于模式串的每个前缀子串,求出其最长的相等的前缀和后缀的长度。
这个长度被称为部分匹配值。
例如,对于模式串"ababc",它的前缀子串有"","a","ab","aba",而其相等的后缀子串有"","c","bc","abc"。
其中,最长的相等的前缀和后缀的长度是2,因此,部分匹配值为2、在KMP算法中,这个信息会被存储在部分匹配表中,即prefix table。
当进行匹配时,如果发现匹配失败,那么根据部分匹配表中的值来进行回溯。
具体来说,如果当前字符匹配失败,那么将模式串向右移动的距离为:当前字符之前的最长相等前缀的长度-1、这样,就可以将模式串与主串对齐继续匹配。
1. 预处理模式串,求出部分匹配表(prefix table)。
2.根据部分匹配表,进行匹配操作。
3.如果匹配成功,返回匹配的位置;否则,返回匹配失败。
总之,KMP算法是一种高效的字符串匹配算法,通过预处理模式串,提供了匹配失败时的快速回溯位置。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
KMP算法的介绍
by sqybi
Chapter 1:KMP算法摘要
首先看一下KMP算法的程序:
Procedure KMP(p, t: String);
Begin
k := 0;
prefix[1] := 0;
For i:=2 To m Do Begin
While (k > 0) And (p[k+1] <> p[i]) Do
k := prefix[k];
If p[k+1] = p[i] Then Inc(k);
prefix[i] := k;
End;
//以上为自身匹配
q := 0;
For i:=1 To n Do Begin
While (q > 0) And (p[q+1] <> t[i]) Do
q := prefix[q];
If p[q+1] = t[i] Then
q := q + 1;
If q = m Then Begin
WriteLn(i-m);
Exit;
End;
End;
End;
从这一段代码,我们可以发现KMP算法的理论基础,即先进行自身匹配,这样再次在主串中查找模式串的话就会节省一些不必要的时间。
首先,模式串自身匹配时需要的时间复杂度是O(m),而在主串中查找的时间复杂度是O(n),这样KMP 算法就可以在O(m+n)的复杂度内完成字符串的匹配,而不是普通查找的O(m*n)的复杂度,可以大大增加程序的速度。
现在大家通过一个简单的例子来看看KMP在进行模式串查找时的方法。
假设在abacabbc中查找acab,这时候先将模式串进行自身匹配,即prefix[3]=1。
当查找的时候,初始状态是这样的,这时q=0。
a b a c a b b c
a c a b
这时我们先比对主串的第一个位置,相同,这时q=1,i=1。
a b a c a b b c
a c a b
再比对第二个位置,不同,此时q=0,i=2。
a b a c a b b c
a c a b
继续对比第三个位置,这次比较不进入语句①,进入语句②,此时q=1,i=3。
a b a c a b b c
a c a b
接下来是第四个位置,对比结束后q=2,i=4。
a b a c a b b c
a c a b
然后是第五个位置,q=3,i=5。
a b a c a b b c
a c a b
最后是第六个位置,q=4,i=6,退出循环。
a b a c a b b c
a c a b
Chapter 2:KMP算法和朴素的匹配算法对比
从上面的分析,我们可以看出KMP算法会比普通算法快很多。
但是有的同学不放心,问道:会不会出现KMP算法比普通算法慢的情况呢?让我们来做个测试吧。
测试机器的配置是Core Duo T2050,1GB内存,80GB PATA 硬盘,GeForce Go 7300显卡。
为了不让硬盘速度影响到程序执行速度,我特意用WinMount软件Mount了一个内存虚拟的磁盘作为程序评测用。
由于Delphi不支持,所以没有使用inline,不过这应该不会影响到程序的速度。
以下是测试结果:
KMP:
comp-0(comp1.in)∷用时 = 0.02s∷空间 = 57.83M
comp-1(comp2.in)∷用时 = 0.02s∷空间 = 57.83M
comp-2(comp3.in)∷用时 = 0.03s∷空间 = 57.83M
comp-3(comp4.in)∷用时 = 0.03s∷空间 = 57.83M
comp-4(comp5.in)∷用时 = 0.05s∷空间 = 57.83M
comp-5(comp6.in)∷用时 = 0.06s∷空间 = 57.83M
comp-6(comp7.in)∷用时 = 0.06s∷空间 = 57.83M
comp-7(comp8.in)∷用时 = 0.36s∷空间 = 57.83M
comp-8(comp9.in)∷用时 = 0.41s∷空间 = 57.83M
comp-9(comp10.in)∷用时 = 0.02s∷空间 = 57.83M
朴素:
comp-0(comp1.in)∷用时 = 0.02s∷空间 = 19.61M
comp-1(comp2.in)∷用时 = 0.02s∷空间 = 19.61M
comp-2(comp3.in)∷用时 = 0.02s∷空间 = 19.61M
comp-3(comp4.in)∷用时 = 0.02s∷空间 = 19.61M
comp-4(comp5.in)∷用时 = 0.06s∷空间 = 19.61M
comp-5(comp6.in)∷用时 = 0.06s∷空间 = 19.61M
comp-6(comp7.in)∷用时 = 0.06s∷空间 = 19.61M
comp-7(comp8.in)∷用时 = 0.47s∷空间 = 19.61M
comp-8(comp9.in)∷用时 = TLE∷空间 = 19.61M
comp-9(comp10.in)∷用时 = 0.28s∷空间 = 19.61M
其中comp-0到comp-7是随机生成的测试数据,主串最长10000000,模式串最长1000000.可以
发现在这些数据中,KMP的优势并不明显,甚至会比朴素的算法慢。
这是因为KMP使用了自身匹配的思想,需要在自身有很多重复的情况下才能很好的体现它的价值。
可以看一下最后两个数据。
这两个数据都是模式串为一长串a加一个b,而主串是一串a。
其中comp-8主串长度为10000000,模式串100000,而comp-9主串长100000,模式串1000。
可以明显发现KMP的速度优势极大,特别是comp-8,KMP 在0.5sec之内就解决了,而朴素的算法在10sec的时限下最后还是TLE了。
这时我们就可以看出KMP最主要的一个优点——稳定。
Chapter 3:学习KMP的好处
可能有的同学会说:Pascal中提供了一个Pos函数,它就是KMP算法写出来的,为什么要学习KMP 呢?
第一点理由,就是Pos函数不能提供所有形式的KMP查找。
比如如果输入的数字范围是maxLongint 的话,Pos函数就无用武之地了。
虽然可以通过转换到antistring进行Pos,但是那样的效率很低。
这时,学会KMP算法就显得很必要了。
但这不是最主要的。
第二点理由,也是最主要的理由,那就是我们可以学会一种思想。
自身匹配是一种很重要的思想,它可以解决很多和KMP看似无关的问题。
我们学习一个算法,学习的不是它的一串代码,而是它的想法。
从而,可以由此衍生出很多其它的想法,也就可以促进其它算法的学习。
这样,我们才能达到学习KMP 的真正目的。