kmp算法简介

合集下载

kmp算法next计算方法

kmp算法next计算方法

kmp算法next计算方法KMP算法是一种用于字符串匹配的经典算法,它的核心在于通过预处理模式串,得到一个next数组,然后利用这个数组在匹配过程中进行快速跳转,从而提高匹配效率。

本文将介绍KMP算法中next数组的计算方法。

在KMP算法中,next数组的含义是指在模式串中,以每个字符结尾的子串中,有多大长度的相同前缀后缀。

这个信息非常有用,因为当遇到不匹配的字符时,我们可以利用next数组中的信息,快速地将模式串向后移动,而不是从头开始逐个字符地比较。

接下来我们来看一下next数组的计算方法。

假设模式串为P,长度为m,我们要计算出next数组的值。

首先,我们定义next[0]=-1,next[1]=0,这两个是特殊情况。

然后,我们从第二个字符开始,依次计算next[i]的值。

具体的计算方法如下:1. 如果P[j]等于P[next[j]],则next[j+1]=next[j]+1;2. 如果P[j]不等于P[next[j]],则需要继续向前寻找,直到找到一个满足P[j]等于P[next[j]]的位置,或者找到0为止。

这样,我们就可以得到整个next数组的值。

这个过程实际上是在模式串中寻找相同的前缀后缀,然后记录下它们的长度。

这样,在匹配过程中,当遇到不匹配的字符时,我们就可以根据next数组中的值,快速地将模式串向后移动,从而提高匹配效率。

需要注意的是,由于next数组的计算是基于模式串本身的特性,因此对于不同的模式串,其next数组的值也是不同的。

这就要求我们在实际使用KMP算法时,需要提前计算好next数组,并将其保存下来,以备匹配过程中使用。

总结一下,KMP算法中next数组的计算方法是一个非常重要的步骤,它直接影响到算法的匹配效率。

通过提前计算好next数组,并在匹配过程中利用它,我们可以大大提高字符串匹配的效率,从而更高效地解决实际问题。

希望本文对KMP算法中next数组的计算方法有所帮助,如果有任何疑问或者建议,欢迎留言讨论。

严蔚敏 数据结构 kmp算法详解

严蔚敏 数据结构 kmp算法详解
max{k|0<k<j,且“t0t1…tk-1”=“tj-ktj-k+1…tj-1” }
当此集合非空时
next[j]= -1 0 当j=0时 其他情况
t=“abab”对应的next数组如下:
j t[j] next[j] 0 a -1 1 b 0 2 a 0 3 b 1
void GetNext(SqString t,int next[]) { int j,k; j=0;k=-1;next[0]=-1; while (j<t.len-1)
既然如此,回溯到si-j+1开始与t匹配可以不做。那 么,回溯到si-j+2 开始与t匹配又怎么样?从上面推理 可知,如果 "t0t1…tj-2"≠"t2t3…tj"
仍然有
"t0t1…tj-2"≠"si-j+2si-j+3…si"
这样的比较仍然“失配”。依此类推,直到对于 某一个值k,使得: "t0t1…tk-2"≠" tj-k+1tj-k+2…tj-1"
b 3
第 1 次匹配
第 2 次匹配
s=aaabaaaa b t=aaaab
第 3 次匹配
s=aaabaaaa b t=aaaab
第 4 次匹配
s=aaabaaaa b t=aaaab
第 5 次匹配
s=aaabaaaa b t=aaaab
上述定义的next[]在某些情况下尚有缺陷。 例如,模式“aaaab”在和主串“aaabaaaab”匹配时, 当i=3,j=3时,s.data[3]≠t.data[3],由next[j]的指示还需 进行i=3、j=2,i=3、j=1,i=3、j=0等三次比较。实际上, 因为模式中的第1、2、3个字符和第4个字符都相等, 因此,不需要再和主串中第4个字符相比较,而可以将模 式一次向右滑动4个字符的位置直接进行i=4,j=0时的 字符比较。

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]。

408中对kmp的考察

408中对kmp的考察

408中对kmp的考察KMP算法是一种用于字符串匹配的高效算法。

在408考试中,可能会出现对KMP算法的考察。

接下来将从算法原理、应用和相关问题等方面进行介绍。

KMP算法的核心思想是利用已经部分匹配的结果来避免不必要的重复比较,从而提高匹配效率。

该算法首先构建一个模式串的部分匹配表,在进行匹配时通过参考该表,根据已匹配的部分字符来确定下一次比较的位置。

具体来说,KMP算法中的部分匹配表是一个数组,其中存储了模式串的前缀子串的最长公共前后缀长度。

通过建立这个表,KMP算法能够在匹配过程中根据已经匹配的部分字符和部分匹配表中的值来决定下一次比较的位置,从而避免不必要的回退操作。

KMP算法广泛应用于字符串匹配问题,例如在文本编辑器中进行关键字搜索、网络爬虫中的网页关键字提取等场景。

其时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度,相较于朴素的字符串匹配算法具有更高的效率。

在408考试中,对KMP算法的考察可能涉及以下内容:1. 理解KMP算法的原理和核心思想,包括构建部分匹配表和利用表进行匹配的过程。

2. 能够手动计算给定字符串和模式串的部分匹配表。

3. 理解KMP算法中的最长公共前后缀概念,以及如何根据已匹配的部分字符和部分匹配表来确定下一次比较的位置。

4. 能够实现KMP算法的代码,包括构建部分匹配表和利用表进行匹配的过程。

5. 分析KMP算法的时间复杂度和空间复杂度,了解其优势和适用性。

总之,对KMP算法的考察可能包括对原理、实现、应用和复杂度等方面的问题。

考生应该深入理解该算法的原理和应用,并熟练掌握其代码实现和分析能力。

KMP算法详解

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算法例题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算法是一种字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。

该算法的核心思想是通过预处理模式串,构建一个部分匹配表,从而在匹配过程中尽量减少不必要的比较。

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

KMP

KMP算法
next函数的改进 函数的改进
aaabaaaab aaaa ① ② ③
j=4 j=3 j=2 j=1 i=4
j
12345
模式 a a a a b next[j] 0 1 2 3 4 nextval[j] 0 0 0 0 4
aaa aa a
aaaab i = 5; j = 1
next[j] = k,而pj=pk, , 主串中s 不等时, 则 主串中 i和pj不等时, 不需再和p 进行比较, 不需再和 k进行比较, 而直接和p 而直接和 next[k]进行比 较.
第 1 次匹配 s= cddcdc t=cdc 第 2 次匹配 s= cddcdc t=cdc 第 3 次匹配 s= cddcdc t=cdc 第 4 次匹配 s= cddcdc t=cdc i= 3 j= 3 i= 2 j= 1 i= 3 j= 1 i= 6 j= 3 成功 失败 失败 失败
i = i –j +2; j = 1;
KMP算法
j 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 模式串 a b c a a b b c a b c a a b d a b next[j] 0 1 1 1 2 2 3 1 1 2 3 4 5 6 7 1 2
nextval[j]
0 1 1 0 2 1 3 1 0 1 1 0 2 1 7 0 1
KMP算法
KMP算法的时间复杂度 KMP算法的时间复杂度 设主串s 的长度为n, 模式串t 长度为m, KMP算 n,模式串 m,在 设主串 s 的长度为 n, 模式串 t 长度为 m, 在 KMP 算 法中求next 数组的时间复杂度为 O(m),在后面的匹 法中求 next数组的时间复杂度为 O(m), 在后面的匹 next 数组的时间复杂度为O(m), 配中因主串s的下标不减即不回溯,比较次数可记为 配中因主串s的下标不减即不回溯, n,所以KMP算法总的时间复杂度为O(n+m). n,所以KMP算法总的时间复杂度为O(n+m). 所以KMP算法总的时间复杂度为O(n+m)
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
i S nex t 0 A -1 1 A 0 2 A 1 3 B 4 A 5 A 6 A 7 D 8
S=AAABAAAD,第2个前缀:AA next[2]=1. 表示S[0…1]的前缀后缀最大值是1 两个前缀:空,A 两个后缀:空,A 显然,next[2]=|A|=1
17
分析S每一个前缀的next值
3
引言
但,只要能把特定模型的基本方法、原理弄 透,不管题目如何变化多端,都万变不离其 中,可以用特定的方法去解决,无非有时需 要配上一些额外技巧、科技罢了。所以,对 于初学算法的人,切勿一开始就对字符串形 成望而生怯的毛病,而应该养成正确思考字 符串问题的好习惯——用算法对应的字符串 性质来解题.
13
重要的话要多讲几遍!
next[i]表示 S[0…i-1] 这个前缀的前缀后缀最 大值! next[i]表示 S[0…i-1] 这个前缀的前缀后缀最 大值! 请务必牢记这个定义!KMP核心部分就是这 个next数组。对next数组的理解透彻与否决 定你能否快速、准确地解决KMP相关的题目 !注意,是S[0…i-1] 不是S[0…i] ! 同时务必正确理解前缀后缀最大值的含义!
i S nex t 0 A -1 1 A 0 2 A 1 3 B 2 4 A 0 5 A 6 A 7 D 8
S=AAABAAAD,第4个前缀:AAAB next[4]=0. 表示S[0…3]的前缀后缀最大值是0 四个前缀:空,A,AA,AAA 四个后缀:空,B,AB,AAB 显然,next[4]=|空|=0
i S nex t 0 A -1 1 A 0 2 A 1 3 B 2 4 A 5 A 6 A 7 D 8
S=AAABAAAD,第3个前缀:AAA next[3]=2. 表示S[0…2]的前缀后缀最大值是2 三个前缀:空,A,AA 三个后缀:空,A,AA 显然,next[3]=|AA|=2
18
分析S每一个前缀的next值
12
前缀后缀最大值
下面我们拿暴力匹配算法中的模板串 S=AAABAAAD 来具体阐述! 我们定义一个数组:int next[N]; next[i]表示 S[0…i-1] 这个前缀的前缀后缀最大 值! 接下来,我们分析字符串S的每一个前缀的 next值,即每一个前缀的前缀后缀最大值。 然后,我们再介绍如果使用这个next数组!
25
KMP 匹配 A A A B A S1
i
S2 j
0
A 0
A A
B
A
A
A
B
A
A
A
D
1
A 1
2
A 2 1
3
B 3 2
4
A 4 0
5
6
7
D 7 3
8
9
1 0
11 1 2
1 3
1 4
1 5
A A 5 1 6 2
8 4
next -1 0
设两个变量 int t1,t2;t1表示当前扫到S1串的位置, t2表示当前扫到S2串的位置。起初,t1=t2=0; S1[t1]=S2[t2]=A,t1++,t2++;//t1=1,t2=1 S1[t1]=S2[t2]=A,t1++,t2++;//t1=2,t2=2 S1[t1]=S2[t2]=A,t1++,t2++;//t1=3,t2=3 S1[t1]=S2[t2]=B,……
15
分析S每一个前缀的next值
i S nex t 0 A -1 1 A 0 2 A 3 B 4 A 5 A 6 A 7 D 8
S=AAABAAAD,第1个前缀:A next[1]=0. 表示S[0…0]的前缀后缀最大值是0 一个前缀:空 一个后缀:空 显然,next[1]=|空|=0
16
分析S每一个前缀的next值
22
分析S每一个前缀的next值
i S nex t 0 A -1 1 A 0 2 A 1 3 B 2 4 A 0 5 A 1 6 A 2 7 D 3 0 8
S=AAABAAAD,第8个前缀:AAABAAAD next[8]=0. 表示S[0…7]的前缀后缀最大值是0
空,A,AA, AAA, AAAB, AAABA, AAABAA, AAABAAA 空,D,AD,AAD, AAAD, BAAAD, ABAAAD, AABAAAD
显然,next[8]=|空|=0
23
得到next数组
i S nex t 0 A -1 1 A 0 2 A 1 3 B 2 4 A 0 5 A 1 6 A 2 7 D 3 0 8
我们得到S串的next数组 再次回忆,next[i]表示S[0…i-1]这个前缀的前 缀后缀最大值。 那么,有什么用呢?! 它与子串匹配有什么关系呢?
21
分析S每一个前缀的next值
i S nex t 0 A -1 1 A 0 2 A 1 3 B 2 4 A 0 5 A 1 6 A 2 7 D 3 8
S=AAABAAAD,第7个前缀:AAABAAA next[7]=3. 表示S[0…6]的前缀后缀最大值是3 空, A, AA, AAA, AAAB, AAABA, AAABAA 空, A, AA, AAA, BAAA, ABAAA, AABAAA 显然,next[7]=|AAA|=3
6
输入和输出
Input 第一行输入一个字符串S1,第二行输入一个 字符串S2,保证0<|S2|<=|S1|<=100000
Output 如果S2是S1的子串,输出“YES”. 否则,输出“NO”.
7
• Sample Input 一个字符串的子串指的是 • AAABAAABAAABAAAD 字符串某一段连续的部分 (比如第一个例子),可 • AAABAAAD 以是其本身。 而不连续的部分,一般称 • ABAAB 作为子序列!(比如第二 • ABB 个例子,ABB是ABAAB的 子序列而不是子串) • Sample Output • YES • NO
9
前缀后缀最大值
• 一个长度为N的字符串S,它有N+1个 前缀(包括空前缀),它有N+1个后缀 (包括空后缀) • 比如ABC,有4个前缀,空,A,AB,ABC 有4个后缀,空,C,BC,ABC • 比如AAA,有4个前缀,空,A,AA,AAA 有4个后缀,空,A,AA,AAA
10
前缀后缀最大值
14
分析S每一个前缀的next值
i S nex t 0 A -1 1 A 2 A 3 B 4 A 5 A 6 A 7 D 8
S=AAABAAAD,第0个前缀:空前缀 空前缀的next值我们直接定义为 -1 即next[0]=-1. 记得之前的“删除前缀、后缀等 于S的<前缀,后缀>”的操作吗? 删除后找不到<前缀,后缀>,next值为-1
27
S1 i
S2 j
KMP匹配
A
0 A 0
A
1 A 1
A
2 A 2 1
B
3 B 3 2
A
4 A 4 0
A
5 A 5 1
A
6 A 6 2
B
7 D 7 3
A
8
A
9
A
1 0
B
1 1
A
1 2
A
1 3
A
1 4
D
1 5
8 4
此时,t1=7, t2=7, S1[t1]=B, S2[t2]=D 出现不相等! 在之前的暴力匹配算法中,这说明了什么? 说明了从 t1=0 这个起始位置开始,往后长度为|S2|的 子串不与S2匹配,那么,在暴力算法中,接下来应该 枚举下一个起始位置 t1=1, 再往下判断, 是吧?但是! 在KMP中有所不同!……
11
前缀后缀最大值
一个字符串S,长度为N. 找出它的N+1个前缀(包括空前缀) 找出它的N+1个后缀(包括空后缀) 按照长度划分,得到N+1对序偶<前缀,后缀> 删除前缀、后缀等于S的<前缀,后缀>,得到 N对<前缀,后缀>。 在这N对中,找到一对满足: 1. 前缀=后缀 2. 前缀后缀的长度最大 该长度就是S的前缀后缀最大值!
next -1 0
29
S1 i
KMP匹配
A 0 A 1 A 2 B 3
A 4
A 5
A 6
B 7
A A S1
i
S2 j
0
A 0
A
A
B
A
A
A
B
A
A
A
D
1
A 1
2
A 2 1
3
B 3 2
4
A 4 0
5
A 5 1
6
A 6 2
7
D 7 3
8
9
1 0
1 1
1 2
1 3
1 4
1 5
8 4
next -1 0
此时t1=t2=3; S1[t1]=S2[t2]=B,t1++,t2++;//t1=t2=4 S1[t1]=S2[t2]=A,t1++,t2++;//t1=t2=5 S1[t1]=S2[t2]=A,t1++,t2++;//t1=t2=6 S1[t1]=S2[t2]=A,t1++,t2++;//t1=t2=7 此时发现,S1[t1] != S2[t2]
举一个容易看出性质的例子,S=ABABABA
前缀 空 A AB ABA ABAB ABABA 后缀 空 A BA ABA BABA ABABA 相等 yes yes no yes no yes
相关文档
最新文档