两种方法实现KMP算法

合集下载

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算法以及优化(代码分析以及求解next数组和nextval数组)

KMP算法以及优化(代码分析以及求解next数组和nextval数组)

KMP算法以及优化(代码分析以及求解next数组和nextval数组)KMP算法以及优化(代码分析以及求解next数组和nextval数组)来了,数据结构及算法的内容来了,这才是我们的专攻,前⾯写的都是开胃⼩菜,本篇⽂章,侧重考研408⽅向,所以保证了你只要看懂了,题⼀定会做,难道这样思想还会不会么?如果只想看next数组以及nextval数组的求解可以直接跳到相应部分,思想总结的很⼲~~⽹上的next数组版本解惑先总结⼀下,⼀般KMP算法的next数组结果有两个版本,我们需要知道为什么会存在这种问题,其实就是前缀和后缀没有匹配的时候next数组为0还是为1,两个版本当然都是对的了,如果next数组为0是的版本,那么对于前缀和后缀的最⼤匹配长度只需要值+1就跟next数组是1的版本⼀样了,其实是因为他们的源代码不⼀样,或者对于模式串的第⼀个下标理解为0或者1,总之这个问题不⽤纠结,懂原理就⾏~~那么此处,我们假定前缀和后缀的最⼤匹配长度为0时,next数组值为1的版本,考研⼀般都是⽤这个版本(如果为0版本,所有的内容-1即可,如你算出next[5]=6,那么-1版本的next[5]就为5,反之亦然)~~其实上⾯的话总结就是⼀句话next[1]=0,j(模式串)数组的第⼀位下标为1,同时,前缀和后缀的最⼤匹配长度+1即为next数组的值,j所代表的的是序号的意思408反⼈类,⼀般数组第⼀位下标为1,关于书本上前⾯链表的学习⼤家就应该有⽬共睹了,书本上好多数组的第⼀位下标为了⽅便我们理解下标为1,想法这样我们更不好理解了,很反⼈类,所以这⾥给出next[1]=0,前缀和后缀的最⼤匹配长度+1的版本讲解前⾔以及问题引出我们先要知道,KMP算法是⽤于字符串匹配的~~例如:⼀个主串"abababcdef"我们想要知道在其中是否包括⼀个模式串"ababc"初代的解决⽅法是,朴素模式匹配算法,也就是我们主串和模式串对⽐,不同主串就往前移⼀位,从下⼀位开始再和模式串对⽐,每次只移动⼀位,这样会很慢,所以就有三位⼤神⼀起搞了个算法,也就是我们现在所称的KMP算法~~代码以及理解源码这⾥给出~~int Index_KMP(SString S,SString T,intt next[]){int i = 1,j = 1;//数组第⼀位下标为1while (i <= S.length && j <= T.length){if (j == 0 || S.ch[i] == T.ch[j]){//数组第⼀位下标为1,0的意思为数组第⼀位的前⾯,此时++1,则指向数组的第⼀位元素++i;++j; //继续⽐较后继字符}elsej = next[j]; //模式串向右移动到第⼏个下标,序号(第⼀位从1开始)}if (j > T.length)return i - T.length; //匹配成功elsereturn 0;}接下来就可以跟我来理解这个代码~~还不会做动图,这⾥就⼿画了~~以上是⼀般情况,那么如何理解j=next[1]=0的时候呢?是的,这就是代码的思路,那么这时我们就知道,核⼼就是要求next数组各个的值,对吧,⼀般也就是考我们next数组的值为多少~~next数组的求解这⾥先需要给出概念,串的前缀以及串的后缀~~串的前缀:包含第⼀个字符,且不包含最后⼀个字符的⼦串串的后缀:包含最后⼀个字符,且不包含第⼀个字符的⼦串当第j个字符匹配失败,由前1~j-1个字符组成的串记为S,则:next[j]=S的最长相等前后缀长度+1与此同时,next[1]=0如,模式串"ababaa"序号J123456模式串a b a b a anext[j]0当第六个字符串匹配失败,那么我们需要在前5个字符组成的串S"ababa"中找最长相等的前后缀长度为多少再+1~~如串S的前缀可以为:"a","ab","aba","abab",前缀只不包括最后⼀位都可串S的后缀可以为:"a","ba","aba","baba",后缀只不包括第⼀位都可所以这⾥最⼤匹配串就是"aba"长度为3,那么我们+1,取4序号J123456模式串a b a b a anext[j]04再⽐如,当第⼆个字符串匹配失败,由前1个字符组成的串S"a"中,我们知道前缀应当没有,后缀应当没有,所以最⼤匹配串应该为0,那么+1就是取1~~其实这⾥我们就能知道⼀个规律了,next[1]⼀定为0(源码所造成),next[2]⼀定为1(必定没有最⼤匹配串造成)~~序号J123456模式串a b a b a anext[j]014再再⽐如,第三个字符串匹配失败,由前两个字符组成的串S"ab"中找最长相等的前后缀长度,之后再+1~~前缀:"a"后缀:"b"所以所以这⾥最⼤匹配串也是没有的长度为0,那么我们+1,取1序号J123456模式串a b a b a anext[j]0114接下来你可以⾃⼰练练4和5的情况~~next[j]011234是不是很简单呢?⾄此,next数组的求法以及kmp代码的理解就ok了~~那么接下来,在了解以上之后,我们想⼀想KMP算法存在的问题~~KMP算法存在的问题如下主串:"abcababaa"模式串:"ababaa"例如这个问题我们很容易能求出next数组序号J123456模式串a b a b a anext[j]011234此时我们是第三个字符串匹配失败,所以我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,可是我们刚开始的时候就已经知道模式串的第三个字符"a"和"c"不匹配,那么这⾥不就多了⼀步⽆意义的匹配了么?所以我们就会有kmp算法的⼀个优化了~~KMP算法的优化我们知道,模式串第三个字符"a"不和主串第三个字符"c"不匹配,next数组需要我们的next[3]=1,也就是下次就是第⼀个字符"a"和主串中第三个字符"c"对⽐,之后就是模式串第⼀个字符"a"不和"c"匹配,就是需要变为next[1]=0,那么我们要省去步骤,不就可以直接让next[3]=0么?序号J12345模式串a b a b anext[j]01123nextval[j]00那么怎么省去多余的步骤呢?这就是nextval数组的求法~~nextval的求法以及代码理解先贴出代码for (int j = 2;j <= T.length;j++){if (T.ch[next[j]] == T.ch[j])nextval[j] = nextval[next[j]];elsenextval[j] = next[j];}如序号J123456模式串a b a b a anext[j]011234nextval[j]0⾸先,第⼀次for循环,j=2,当前序号b的next[2]为1,即第⼀个序号所指向的字符a,a!=当前序号b,所以nextval[2]保持不变等于next[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]01第⼆次for循环,j=3,当前序号a的next[3]为1,即第⼀个序号所指向的字符a,a=当前序号a,所以nextval[3]等于nextval[1]=0序号J123456模式串a b a b a anext[j]011234nextval[j]010第三次for循环,j=4,当前序号b的next[4]为2,即第⼆个序号所指向的字符b,b=当前序号b,所以nextval[4]等于nextval[2]=1序号J123456模式串a b a b a anext[j]011234nextval[j]0101就是这样,你可以练练5和6,这⾥直接给出~~序号J123456模式串a b a b a anext[j]011234nextval[j]010104⾄此nextval数组的求法你也应该会了,那么考研要是考了,那么是不是就等于送分给你呢?⼩练习那么你试着来求⼀下这个模式串的next和nextval数组吧~~next[j]nextval[j]⼩练习的答案序号j12345模式串a a a a b next[j]01234 nextval[j]00004。

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算法概念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算法next函数详解KMP算法在介绍KMP算法之前,先介绍⼀下BF算法。

⼀.BF算法BF算法是普通的模式匹配算法,BF算法的思想就是将⽬标串S的第⼀个字符与模式串P的第⼀个字符进⾏匹配,若相等,则继续⽐较S的第⼆个字符和P的第⼆个字符;若不相等,则⽐较S的第⼆个字符和P的第⼀个字符,依次⽐较下去,直到得出最后的匹配结果。

举例说明:S: ababcababaP: ababaBF算法匹配的步骤如下i=0 i=1 i=2 i=3 i=4第⼀趟:a babcababa 第⼆趟:a b abcababa 第三趟:ab a bcababa 第四趟:aba b cababa 第五趟:abab c ababaa baba ab aba ab a ba aba b a abab aj=0 j=1 j=2 j=3 j=4(i和j回溯)i=1 i=2 i=3 i=4 i=3第六趟:a b abcababa 第七趟:ab a bcababa 第⼋趟:aba b cababa 第九趟:abab c ababa 第⼗趟:aba b cababaa baba a baba ab aba ab a ba a babaj=0 j=0 j=1 j=2(i和j回溯) j=0i=4 i=5 i=6 i=7 i=8第⼗⼀趟:abab c ababa 第⼗⼆趟:ababc a baba 第⼗三趟:ababca b aba 第⼗四趟:ababcab a ba 第⼗五趟:ababcaba b aa baba a baba ab aba ab a ba aba b aj=0 j=0 j=1 j=2 j=3i=9第⼗六趟:ababcabab aabab aj=4(匹配成功)代码实现:int BFMatch(char*s,char*p){int i,j;i=0;while(i<strlen(s)){j=0;while(s[i]==p[j]&&j<strlen(p)){i++;j++;}if(j==strlen(p))return i-strlen(p);i=i-j+1; //指针i回溯}return-1;}其实在上⾯的匹配过程中,有很多⽐较是多余的。

文本精准匹配检索方法

文本精准匹配检索方法

文本精准匹配检索方法文本精准匹配检索方法是一种常用的信息检索方法,它能够实现对文本信息的快速检索与过滤。

本文将对文本精准匹配检索方法进行介绍,主要内容包括精准匹配原理、算法实现和应用场景等方面。

一、精准匹配原理文本精准匹配是指在大量文本中查找与指定关键词完全一致的文本。

其原理是将关键词与文本进行逐个字符的比较,如果每个字符都完全一致,则匹配成功。

由于是逐个字符比较,因此该方法适用于文本内容较少的情况。

在文本内容较多的情况下,该方法会出现效率低下和计算复杂度高的问题,因此需要采用更高级的文本检索算法来进行优化。

二、算法实现为了实现文本精准匹配,我们需要编写一定的程序算法来对文本进行处理。

下面介绍两种常见的算法实现方法。

1.暴力匹配算法暴力匹配算法是一种最简单而且最直接的文本匹配算法。

它的基本思想是将两个字符串从头开始逐个字符地比较,当两个字符不同时就将比较下一个字符,直到找到匹配的字符串或者比较到其中一个字符串的结束位置。

缺点:该算法的时间复杂度较高,当文本内容较多时,计算复杂度会非常高,因此不适用于大规模文本匹配。

2.KMP算法KMP算法是在暴力匹配算法的基础上进行了优化,它通过预先计算一个跳转表格,来匹配被查找字符串在匹配字符串中出现的位置。

具体实现:假设我们要匹配的文本为t,被匹配的字符串为s。

我们需要维护一个跳转表格next,其中next[i]表示当t[i]和s[j]不匹配时,下一次应该匹配的位置。

当出现不匹配的情况时,我们可以直接跳过一部分字符,而不是从头开始重新匹配。

这样可以有效降低匹配的时间复杂度。

算法具体步骤如下:(1)对被匹配字符串s进行预处理,生成跳转表格next。

(2)从文本t的第一个字符开始,逐个字符地与s中的字符进行比较,如果不相同,则根据跳转表格next中的指示进行跳转,直到找到匹配的位置或者匹配结束。

(3)匹配结束后,我们可以得到匹配的位置或者匹配失败的结果,根据具体的需求进行后续处理。

kmp算法pmt的值

kmp算法pmt的值

kmp算法pmt的值PMT的值是KMP算法中的一个重要概念,它代表了模式串中每个位置上的最长相同前缀后缀的长度。

在KMP算法中,PMT的值被用来确定当遇到不匹配字符时,模式串应该向右移动的位置,以提高匹配的效率。

KMP算法是一种字符串匹配算法,用于在一个文本串中查找一个模式串的出现位置。

与暴力匹配算法相比,KMP算法具有更高的效率。

PMT的值的计算是KMP算法中的关键步骤之一,下面将详细介绍PMT 的计算方法。

我们需要了解最长相同前缀后缀的概念。

对于一个字符串,它的前缀是指从开头到某个位置的子串,后缀是指从某个位置到末尾的子串。

例如,字符串"abcabc"的前缀有"","a","ab","abc",后缀有"","c","bc","abc"。

最长相同前缀后缀即是指一个字符串既是它的前缀,又是它的后缀,并且长度最长。

在KMP算法中,我们通过计算模式串的PMT数组来得到每个位置上的最长相同前缀后缀的长度。

具体计算过程如下:1. 初始化PMT数组,将第一个位置的值设为0。

2. 从第二个位置开始,依次计算每个位置上的PMT值。

3. 假设当前位置为i,PMT[i-1]表示前一个位置上的最长相同前缀后缀的长度。

我们需要判断当前位置的字符是否与PMT[i-1]位置上的字符相等。

- 如果相等,那么当前位置上的最长相同前缀后缀的长度就是PMT[i-1]+1。

- 如果不相等,我们可以利用PMT数组来找到一个更短的相同前缀后缀,并继续判断是否相等。

4. 重复步骤3,直到计算完所有位置上的PMT值。

通过上述步骤,我们就可以得到模式串的PMT数组。

在KMP算法中,当遇到不匹配字符时,我们可以利用PMT数组来确定模式串向右移动的位置。

具体操作如下:假设当前文本串的位置为i,模式串的位置为j。

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

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

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算法解析摘要:模式匹配是字符串的基本运算之一,也是数据结构教学中的难点之一。

分析了模式匹配KMP算法以及算法中next函数的含义,给出了next函数的两种实现方法,有助于在教学实践中帮助学生更好地理解该算法。

关键词:数据结构;模式匹配;KMP算法0引言模式匹配(Patten Matching)是许多计算机应用领域的基础问题,在数据结构中模式匹配是字符串的基本运算之一。

字符串模式匹配指的是,找出特定的模式串在一个较长的字符串中出现的位置。

有两个字符串S和T,字符串S称为目标串,字符串T称为模式串,要求找出模式T在S中的首次出现的位置。

一旦模式T在目标S中找到,就称发生一次匹配。

有些应用可能会要求找出所有的匹配位置<sup>[1]</sup>。

例如,目标串S= 'Shanghai',模式串T= 'gha',则匹配结果为4。

模式匹配的典型算法包括朴素匹配算法、KMP算法和BM算法等,其中KMP算法是效率较高且经典的模式匹配算法之一<sup>[2]</sup>。

在数据结构教学中,由于KMP算法较难理解,课堂讲授往往很难取得好的效果。

本文通过对传统的朴素匹配算法与KMP算法的比较,分析next函数的含义以及实现方法,来帮助理解KMP算法。

1朴素匹配算法在朴素匹配算法中,S和T分别为目标串和模式串,变量i和j 为两个静态指针,分别表示S和T中当前正待比较的字符位置。

算法的基本思想是:第1趟匹配:从S的第1个字符(序号为0)起和T的第一个字符比较之,如果相等,则继续逐个比较后续字符(i++;j++),否则开始下一趟匹配。

新的一趟匹配:i的初值为上一趟的初值+1 ,j的初值为1,如果比较结果相等,则继续逐个比较后续字符,否则开始下一趟匹配。

依次类推,直至某一趟匹配中,T的每个字符依次和S中的一个连续的字符序列相等,则称匹配成功,否则称匹配不成功。

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算法是一种更加高效的算法,它不需要回溯匹配过的字符,在匹配失败的时候,根据已经匹配的字符和模式串前缀的匹配关系直接跳跃到下一次匹配的起点。

下面,我将详细介绍KMP算法原理及其实现。

1. KMP算法原理KMP算法的核心思想是:当模式串中的某个字符与文本串中的某个字符不相同时,根据已经匹配的字符和模式串前缀的匹配关系,跳过已经比较过的字符,从未匹配的字符开始重新匹配。

这个过程可以通过计算模式串的前缀函数(即next数组)来实现。

具体地,假设现在文本串为T,模式串为P,它们的长度分别为n和m。

当对于文本串T的第i个字符和模式串P的第j个字符(i和j都是从0开始计数的)进行匹配时:如果T[i]和P[j]相同,则i和j都加1,继续比较下一个字符;如果T[i]和P[j]不同,则j回溯到next[j](next[j]是P[0]到P[j-1]的一个子串中的最长的既是自身的前缀又是后缀的子串的长度),而i不会回溯,继续和P[next[j]]比较。

如果匹配成功,则返回i-j作为P在T中的起始位置;如果匹配失败,则继续执行上述过程,直到文本串T被遍历完或匹配成功为止。

2. KMP算法步骤(1)计算模式串的前缀函数next[j]。

next[j]表示P[0]到P[j-1]的一个子串中的最长的既是自身的前缀又是后缀的子串的长度。

具体计算方式如下:先令next[0]=-1,k=-1(其中k表示相等前缀的长度,初始化为-1),j=0。

从j=1向后遍历整个模式串P:如果k=-1或者P[j]=P[k],则next[j+1]=k+1,k=j,j+1;否则,令k=next[k],再次执行步骤2。

(2)使用next数组进行匹配。

从文本串T的第0个字符开始,从模式串P的第0个字符开始匹配,如果匹配失败,根据next数组进行回溯。

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为模式串的长度。

两种常见的模式匹配算法(代码实现)

两种常见的模式匹配算法(代码实现)

两种常见的模式匹配算法(代码实现)BF算法(暴⼒法)不多解释,直接上代码:// BF算法 O(mn)int bf(SString s, SString t, int pos){int i = pos, j = 0;while (i < s.length && j < t.length){if (s.ch[i] == t.ch[j]){i++;j++;} else {i = i - j + 1;j = 0;}}if (j >= t.length)return i - t.length;elsereturn -1;}// 另⼀个版本的BF算法 - O(mn)int pm(SString s, SString t, int pos){for (int i = pos; i <= s.length-t.length; i++){bool status = true;for (int j = 0; j < t.length; j++){if (s.ch[i+j] != t.ch[j]){status = false;break;}}if (status)return i;}return -1;}KMP算法KMP算法较难理解,在⼤⼆上数据结构这门课的时候就没有搞懂,今天花了点时间终于把它看懂了。

KMP算法相⽐BF算法,其改进主要在使⽤了⼀个前后缀匹配数组next(我⾃⼰起的名⼉~)来记录前缀和后缀的匹配信息,以使得在发现主串与模式串的⽐较中出现不匹配时,主串指针⽆需回溯,并根据前后缀匹配数组中的信息,向后移动,从⽽减少了多余的⽐较。

代码实现:// KMP算法int kmp(SString &s, SString &t, int pos){int next[t.length], j = 0, i = 0;get_next(t, next);while (i < s.length && j < t.length){if (j == -1 || s.ch[i] == t.ch[j]){i++; j++;} elsej = next[j];}if (j >= t.length)return i-t.length;elsereturn -1;}void get_next(SString &t, int next[]){ int i = 0, j = -1;next[0] = -1;while (i < t.length - 1){if (j == -1 || t.ch[i] == t.ch[j]){i++; j++;next[i] = j;} else {j = next[j];}}}参考博客:(讲得⾮常好,但是没有代码实现)(进⼀步理解)(含代码实现)可运⾏的整体代码:#include<iostream>#define MAXLEN 100#define CHUNKSIZE 50using namespace std;// 串的普通顺序存储typedef struct {char ch[MAXLEN+1];int length;}SString;// 串的堆式顺序存储//typedef struct {// char *ch;// int length;//}SString;// 串的链式存储typedef struct chunk{char ch[CHUNKSIZE];struct chunk *next;}Chunk;typedef struct {Chunk *head, *tail;int length;}LString;// 普通顺序存储的初始化操作void SsInit(SString &s){s.length = 0;}void SsInput(SString &s){char c;while ((c = getchar()) != '\n'){s.ch[s.length++] = c;}}void printString(SString &s){for (int i = 0; i < s.length; i++){cout << s.ch[i];}cout << endl;}// BF算法 - O(mn)int pm(SString s, SString t, int pos){for (int i = pos; i <= s.length-t.length; i++){ bool status = true;for (int j = 0; j < t.length; j++){if (s.ch[i+j] != t.ch[j]){status = false;break;}}if (status)return i;}return -1;}// 另⼀种版本的BF算法 O(mn) - 与暴⼒法相似int bf(SString s, SString t, int pos){int i = pos, j = 0;while (i < s.length && j < t.length){if (s.ch[i] == t.ch[j]){i++;j++;} else {i = i - j + 1;j = 0;}}if (j >= t.length)return i - t.length;elsereturn -1;}// KMP算法int kmp(SString &s, SString &t, int pos){int next[t.length], j = 0, i = 0;get_next(t, next);while (i < s.length && j < t.length){if (j == -1 || s.ch[i] == t.ch[j]){i++; j++;} elsej = next[j];}if (j >= t.length)return i-t.length;elsereturn -1;}void get_next(SString &t, int next[]){int i = 0, j = -1;next[0] = -1;while (i < t.length - 1){if (j == -1 || t.ch[i] == t.ch[j]){i++; j++;next[i] = j;} else {j = next[j];}}}int main(){SString s, t;SsInit(s);SsInput(s);SsInit(t);SsInput(t);int loc = -1;// loc = pm(s, t, 0); // loc = bf(s, t, 0);loc = kmp(s, t, 0); cout << loc << endl; }。

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算法,全称为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算法测试用例

kmp算法测试用例

kmp算法测试用例KMP算法测试用例KMP算法是一种高效的字符串匹配算法,它能够在一个主串中快速查找一个模式串的位置。

在软件开发中,字符串匹配是一个非常常见的问题,如文本搜索、数据处理、编译器等都需要用到字符串匹配算法。

KMP算法以其高效的匹配速度和较低的时间复杂度成为了字符串匹配算法的首选之一。

一、KMP算法的原理KMP算法通过预处理模式串,构建一个部分匹配表(Partial Match Table),然后通过该表减少不必要的比较次数,提高算法的效率。

KMP算法的核心思想是,当在主串中匹配到某个字符与模式串不匹配时,通过部分匹配表找到一个可以跳过多个字符的位置,从而减少比较的次数。

二、KMP算法的实现KMP算法的实现分为两个步骤:预处理和匹配。

首先对模式串进行预处理,构建部分匹配表。

然后在主串中进行匹配,根据部分匹配表的结果决定移动的位置。

下面以一个测试用例来说明KMP算法的实现过程。

假设主串为:"ABABABABCABABABABCABABABABC",模式串为:"ABABABC"。

1. 预处理首先计算模式串的部分匹配表,该表用于存储模式串中每个前缀的最长相同前缀和后缀的长度。

例如,对于模式串"ABABABC",其部分匹配表为[0, 0, 1, 2, 3, 0, 1]。

2. 匹配在主串中按照KMP算法进行匹配。

首先将模式串与主串的第一个字符进行比较,发现不匹配,根据部分匹配表得到需要移动的位置。

由于模式串的第一个字符不匹配,根据部分匹配表的结果,移动的位置为3。

然后将模式串向右移动3位,与主串的第四个字符进行比较。

接下来的匹配过程如下:- 模式串与主串的第四个字符进行比较,发现不匹配,根据部分匹配表得到需要移动的位置为3。

将模式串向右移动3位,与主串的第七个字符进行比较。

- 模式串与主串的第七个字符进行比较,发现匹配,继续比较下一个字符。

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. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

两种方法实现KMP算法
方法一:暴力匹配法
暴力匹配法是KMP算法的一种简单实现方式,其思路是遍历主串和模式串,逐个字符进行比较。

如果匹配失败,则将模式串右移一位,继续与主串进行匹配。

首先,我们需要理解KMP算法中的next数组的含义。

next数组用于记录模式串中出现不匹配时,下一步模式串应该移动到的位置。

具体求解next数组的方法有多种,其中最简单的方法是通过递归实现。

以下是一个使用暴力匹配法实现KMP算法的示例代码:
```python
def kmp(text, pattern):
n = len(text)
m = len(pattern)
next = getNext(pattern)
i=0
j=0
while i < n and j < m:
if text[i] == pattern[j]:
i+=1
j+=1
else:
if j == 0:
i+=1
else:
j = next[j-1] + 1
if j == m:
return i - m
else:
return -1
def getNext(pattern):
n = len(pattern)
next = [-1] * n
for i in range(1, n):
j = next[i-1]
while pattern[i] != pattern[j+1] and j >= 0: j = next[j]
if pattern[i] == pattern[j+1]:
next[i] = j + 1
else:
next[i] = -1
return next
```
在上述代码中,kmp函数接收两个参数text和pattern,分别表示主串和模式串。

函数中先获取模式串的next数组,然后利用while循环进行暴力匹配。

如果匹配成功,返回主串中模式串的起始索引;否则,返回-1
通过该方法实现KMP算法的时间复杂度为O(n*m),其中n为主串的长度,m为模式串的长度。

方法二:优化方法(KMP算法)
KMP算法通过空间换时间的方式优化了匹配过程,使得时间复杂度为O(n+m),其中n为主串的长度,m为模式串的长度。

以下是KMP算法的实现代码:
```python
def kmp(text, pattern):
n = len(text)
m = len(pattern)
next = getNext(pattern)
i=0
j=0
while i < n and j < m:
if text[i] == pattern[j]: i+=1
j+=1
else:
if j == 0:
i+=1
else:
j = next[j-1]
if j == m:
return i - m
else:
return -1
def getNext(pattern):
n = len(pattern)
next = [-1] * n
i=0
j=-1
while i < n - 1:
if j == -1 or pattern[i] == pattern[j]:
i+=1
j+=1
next[i] = j
else:
j = next[j]
return next
```
在上述代码中,kmp函数和getNext函数的实现与前面的方法一相同。

不同之处在于,在KMP算法中,模式串移动的位置可以根据next数组直
接获取,无需进行额外的判断。

通过这种优化,KMP算法的时间复杂度得以优化为O(n+m)。

总结:
KMP算法通过next数组记录了模式串的失配情况,从而避免了重复
比较已经匹配过的字符串。

通过对next数组的计算和优化,使得匹配过
程变得更加高效。

以上给出的两种方法分别是通过暴力匹配和KMP算法两
种方式实现的,其中KMP算法的优化方法相对更高效。

相关文档
最新文档