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)

kmp next算法

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算法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百度百科

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

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 时间复杂度计算

kmp 时间复杂度计算

kmp 时间复杂度计算摘要:一、KMP 算法简介1.KMP 算法的概念2.KMP 算法的原理3.KMP 算法的作用二、KMP 算法的时间复杂度分析1.KMP 算法的时间复杂度公式2.KMP 算法时间复杂度分析的过程3.KMP 算法相对于其他字符串匹配算法的优势三、KMP 算法在实际应用中的案例1.KMP 算法在文本处理中的应用2.KMP 算法在信息检索中的应用3.KMP 算法在自然语言处理中的应用正文:一、KMP 算法简介KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,用于在一个主字符串中查找一个子字符串出现的位置。

该算法由Donald Knuth、Charles Morris 和Vaughan Pratt 于1977 年共同提出,其核心思想是利用子字符串的前缀与后缀信息来避免不必要的字符比较,从而提高匹配速度。

1.KMP 算法的概念:KMP 算法是一种滑动窗口法,通过构建一个“部分匹配表”(也称为“失效函数”或“next 数组”),实现字符串的高效匹配。

2.KMP 算法的原理:从主字符串的第一个字符开始,将其与子字符串的第一个字符进行比较。

若相等,继续比较后续字符;若不等,根据部分匹配表的值,将子字符串向右移动若干个字符,再次进行比较。

如此循环,直至找到匹配的子字符串或到达子字符串末尾。

3.KMP 算法的作用:KMP 算法可以在O(n) 的时间复杂度内完成主字符串与子字符串的匹配,其中n 为字符串的长度。

相较于O(n^2) 的暴力匹配算法,KMP 算法具有较高的效率。

二、KMP 算法的时间复杂度分析1.KMP 算法的时间复杂度公式:最优情况下,KMP 算法的时间复杂度为O(n),其中n 为字符串的长度。

最坏情况下,KMP 算法的时间复杂度为O(n^2),此时子字符串与主字符串的前缀完全相同。

2.KMP 算法时间复杂度分析的过程:分析KMP 算法的时间复杂度,需要考虑最优情况、最坏情况和平均情况。

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

KMP算法(推导方法及模板)

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算法的时间复杂度KMP算法是一种字符串匹配算法,它可以在一个主串中高效地查找所有匹配某个模式串的位置。

在计算机科学中,算法的时间复杂度是衡量算法执行时间与输入规模之间关系的度量。

在本文中,我们将深入探讨KMP算法的时间复杂度。

KMP算法的时间复杂度可通过三个方面来分析:预处理阶段的时间复杂度、匹配阶段的时间复杂度以及总体时间复杂度。

1. 预处理阶段的时间复杂度在KMP算法中,要先对模式串进行预处理,生成部分匹配表(Partial Match Table),也称为最长公共前后缀表(Longest Proper Prefix which is also Sufix,简称为LPS表)。

这个过程的时间复杂度是O(m),其中m是模式串的长度。

在生成部分匹配表的过程中,KMP算法利用了前缀与后缀的性质,通过动态规划的方式计算每个位置的最长匹配长度。

虽然这个过程需要遍历整个模式串,但是每次计算的操作都具有重叠子问题的性质,因此可以通过状态转移方程高效地计算出来。

2. 匹配阶段的时间复杂度在匹配阶段,KMP算法将主串与模式串进行逐个字符的比较,并利用已经生成的部分匹配表来决定下一次比较的位置。

这个过程的时间复杂度是O(n),其中n是主串的长度。

在匹配过程中,KMP算法利用了部分匹配表的信息,根据当前位置的匹配长度来确定下一次比较的位置。

通过避免无效的比较,KMP 算法可以在最坏情况下实现线性的时间复杂度。

3. 总体时间复杂度KMP算法的总体时间复杂度是预处理阶段的时间复杂度与匹配阶段的时间复杂度之和。

即O(m) + O(n) = O(m + n)。

从总体时间复杂度可以看出,KMP算法的执行时间与主串和模式串的长度之和成正比。

相比于朴素的字符串匹配算法,KMP算法可以大大提高匹配的效率,尤其是在模式串较长的情况下。

总结:KMP算法的时间复杂度是O(m + n),其中m是模式串的长度,n是主串的长度。

通过对模式串进行预处理并利用部分匹配表的信息,KMP算法可以高效地在主串中查找所有匹配模式串的位置。

kmp算法python代码

kmp算法python代码

kmp算法python代码摘要:1.KMP 算法简介2.KMP 算法的Python 实现3.KMP 算法的应用示例正文:1.KMP 算法简介KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,用于在一个主字符串中查找一个子字符串出现的位置。

该算法的关键在于通过预处理子字符串,减少不必要的字符比较,从而提高匹配速度。

2.KMP 算法的Python 实现以下是KMP 算法的Python 实现:```pythondef compute_prefix_function(pattern):m = len(pattern)prefix_function = [0] * (m + 1)prefix_function[0] = 0i, j = 1, 0while i < m:if pattern[i] == pattern[j]:j += 1prefix_function[i] = ji += 1else:if j!= 0:j = prefix_function[j - 1]else:prefix_function[i] = 0i += 1return prefix_functiondef kmp_search(text, pattern):m, n = len(text), len(pattern)prefix_function = compute_prefix_function(pattern) i, j = 0, 0while i < m:if pattern[j] == text[i]:i += 1j += 1if j == n:return i - jelif i < m and pattern[j]!= text[i]:if j!= 0:j = prefix_function[j - 1]else:i += 1return -1if __name__ == "__main__":text = "我国是一个伟大的国家"pattern = "伟大的"result = kmp_search(text, pattern)if result!= -1:print("子字符串"{}" 在主字符串中第{} 位置出现。

KMP算法实现及优化方法

KMP算法实现及优化方法

KMP算法实现及优化方法KMP算法(Knuth-Morris-Pratt算法)是一种字符串匹配算法,用于在一个主文本字符串S内查找一个模式字符串P的出现位置。

KMP算法利用模式字符串中前缀和后缀的信息来跳过不必要的比较,从而提高查找的效率。

KMP算法的基本思想是,当出现不匹配时,通过已经部分匹配的信息,可以确定一部分字符是匹配的,可以直接跳过这部分已经匹配的字符,继续进行比较。

这个部分匹配的信息,就是模式字符串P自身的前缀和后缀的最长共有元素的长度,也称为前缀函数或部分匹配表。

1.构建部分匹配表:对模式字符串P进行分析,计算出每个位置的最长共有元素的长度,存储在一个部分匹配表中。

2.在主文本字符串S中进行匹配:从主文本字符串的第一个位置开始,逐个字符与模式字符串进行比较,如果字符相等则继续比较下一个字符,如果字符不相等,则根据部分匹配表跳过一部分字符,继续比较,直到找到匹配的位置或者比较结束。

优化KMP算法可以从两方面进行:1.改进部分匹配表的构建:KMP算法中最耗时的部分是部分匹配表的构建,可以对其进行优化。

一种优化方法是使用动态规划思想,利用已计算的部分匹配值来计算新的部分匹配值,从而减少计算量。

2.改进模式字符串的跳过方式:KMP算法中,当在主文本字符串S中比较到一些位置时,如果字符不匹配,则根据部分匹配表来跳过一部分字符。

可以根据具体问题的特点,利用更加有效的跳过方式来提高算法的效率。

一种常见的跳过方式是使用好后缀和坏字符的信息,来决定向右移动的步数。

总结起来,KMP算法是一种高效的字符串匹配算法,通过部分匹配表的构建和优化,可以在O(n+m)的复杂度内完成匹配。

在实际应用中,根据具体问题的特点,可以进一步改进KMP算法来提高效率。

kmp算法c语言代码

kmp算法c语言代码

kmp算法c语言代码KMP算法C语言代码KMP算法是一种字符串匹配算法,它的核心思想是利用已知信息来避免无效的比较,从而提高匹配效率。

KMP算法的实现需要用到一个next数组,它记录了模式串中每个位置之前的最长公共前后缀的长度。

下面是KMP算法的C语言代码实现:```cvoid getNext(char* pattern, int* next) {int i = 0, j = -1;next[0] = -1;while (pattern[i]) {if (j == -1 || pattern[i] == pattern[j]) {i++;j++;next[i] = j;} else {j = next[j];}}}int kmp(char* text, char* pattern) {int i = 0, j = 0;int text_len = strlen(text);int pattern_len = strlen(pattern);int* next = (int*)malloc(sizeof(int) * pattern_len); getNext(pattern, next);while (i < text_len && j < pattern_len) {if (j == -1 || text[i] == pattern[j]) {i++;j++;} else {j = next[j];}}free(next);if (j == pattern_len) {return i - j;} else {return -1;}}```在上面的代码中,getNext函数用来计算next数组,kmp函数用来进行字符串匹配。

在getNext函数中,i表示当前位置,j表示最长公共前后缀的长度。

如果当前位置和最长公共前后缀的下一个位置相等,那么最长公共前后缀的长度加1;否则,j跳到next[j]的位置。

  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
相关文档
最新文档