深度剖析KMP

深度剖析KMP,让你认识真正的NextKMP算法,想必大家都不陌生,它是求串匹配问题的一个经典算法(当然如果你要理解成放电影的KMP,请退出本页面直接登录各大电影网站,谢谢),我想很多人对它的理解仅限于此,知道KMP能经过预处理然后实现O(N*M)的效率,比brute force(暴力算法)更优秀等等,其实KMP算法中的Next函数,功能十分强大,其能力绝对不仅仅限于模式串匹配,它并不是KMP的附属品,其实它还有更多不为人知的神秘功能^_^先来看一个Next函数的典型应用,也就是模式串匹配,这个相信大家都很熟悉了:POJ 3461 Oulipo——很典型的模式串匹配问题,求模式串在目标串中出现的次数。

#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define MAX 1000001char t[MAX];char s[MAX];int next[MAX];inline void calnext(char s[],int next[]){int i;int j;int len=strlen(s);next[0]=-1;j=-1;for(i=1;i<len;i++){while(j>=0&&s[i]!=s[j+1])j=next[j];if(s[j+1]==s[i])//上一个循环可能因为j=-1而不做,此时不能知道s[i]与s[j+1]的关系。

故此需要此条件。

j++;next[i]=j;}}int KMP(char t[],char s[]){int ans=0;int lent=strlen(t);int lens=strlen(s);if(lent<lens)return 0;int i,j;j=-1;for(i=0;i<lent;i++){while(j>=0&&s[j+1]!=t[i])j=next[j];if(s[j+1]==t[i])j++;if(j==lens-1){ans++;j=next[j];}}return ans;}int main(){int testcase;scanf("%d",&testcase);int i;for(i=1;i<=testcase;i++){scanf("%s%s",s,t);calnext(s,next);printf("%d\n",KMP(t,s));}return 0;}—————————————————————————————————————————————POJ 2406 Power Strings这道题就比较有意思了,乍看之下,怎么看貌似都与KMP无关,呵呵,这就是因为你没有深入理解Next 的含义;我首先来解释下这道题的题意,给你一个长度为n的字符串,首先我们找到这样一个字符串,这个字符串满足长度为n的字符串是由这个字符串重复叠加得到并且这个字符串的长度要最小.,然后输出重复的次数。

比如说,ababab这个字符串,显然它是由ab重复叠加3次得到,所以,答案输出3.那么这个题用next怎么做呢,我们必须知道,next数组里面存放的是如果当前匹配失败,模式串可以继续进行匹配的下一个位置。

For Example:1 2 3 4 5 6S= a b a b a ?Next= 0 0 1 2 3 ?其中next[5]=3,说明如果模式串在j=6处匹配失败,那么j=next[5]=3 ,为什么? 因为S的头三位和末三位是一样的,如果说S已经匹配到5的位置(匹配到5说明前5位都已经匹配上),那么前三位肯定也匹配上了(废话~),若果这个时候要继续匹配,我们可以将模式串向右平移几个个单位,这样保证S的前三位仍然是可以匹配上的。

比如说目标串是i= 1 2 3 4 5 6 7 8 9a b a b a d e f ga b a b a cj= 1 2 3 4 5 6next= 0 0 1 2 3 ?现在我们发现i=6与j=6两串不匹配怎么办?由于next[5]指向3,那么我们将模式串平移i= 1 2 3 4 5 6 7 8 9a b a b a d e f ga b a b a cj= 1 2 3 4 5 6next= 0 0 1 2 3 ?这样我们从j=3处继续向后匹配。

(当然如果此时i=6与j=4仍然不匹配,那么我们继续使用失败函数,去寻找下一个位置)好的,现在我们已经知道了,next数组中所存放的数字的含义,那么接下来让我们来看看怎样灵活的使用next,揭开它不为人知的另一面吧。

回到原题,原题要求求出一个字符串的某一个子串,使得这个字符串不断自我叠加后得到原串,并且这个重复的次数最多。

那么它和next有什么关系呢???结论:如果有一个字符串s,长度是len,它的失败函数是next,如果len能被len-next[len]整除,那么len-next[len]就是我们要求的那个子串的长度,与之对应的字符串,就是我们想得到的子串;为什么呢?假设我们有一个字符串ababab,那么next[6]=4对吧,由于next的性质是,匹配失败后,下一个能继续进行匹配的位置,也就是说,把字符串的前四个字母,abab,平移2个单位,这个abab一定与原串的abab重合(否则就不满足失败函数的性质),这说明了什么呢,由于字符串进行了整体平移,而平移后又要重叠,那么必有s[1]=s[3],s[2]=s[4],s[3]=s[5],s[4]=s[6].说明长度为2的字符串在原串中一定重复出现,这就是len-next[len]的含义!解决上面这个问题的同时,其实还有另一个问题,那就是如果这个字符串长度为奇数怎么办?如ababa,好像next[len]也等于3呢,可是aba-ba-似乎并不是由ba重复得到的吧。

我们先把这个字符串断开,ab-ab-a,可以想象,中间的ab平移后,没有ab与它重合(只能重合一个,这虽然没有违背next的性质,但是却对本题的方法造成了影响,请读者细细品味),所以才会出现上面的情况!所以要加上len能够整除len-next[len]这个条件.此题源代码如下://This is the source code for POJ 2406//coded by abilitytao//2009年7月31日11:17:34#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define MAX 1000001int next[MAX];inline void calnext(char s[],int next[]){int i;int j;int len=strlen(s);next[0]=-1;j=-1;for(i=1;i<len;i++){while(j>=0&&s[i]!=s[j+1])j=next[j];if(s[j+1]==s[i])j++;next[i]=j;}}int main(){int n;char str[MAX];int len;while(scanf("%s",&str)){if(str[0]=='.')break;len=strlen(str);calnext(str,next);if((len)%(len-1-next[len-1])==0)printf("%d\n",(len)/(len-1-next[len-1]));else{putchar('1');putchar('\n');}}return 0;}POJ 1961与上题类似,故不赘述,代码如下://This is the source code for POJ 1961//coded by abilitytao//2009年7月31日10:56:07#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>using namespace std;#define MAX 1000001int next[MAX];void calnext(char s[],int next[]){int i;int j;int len=strlen(s);next[0]=-1;j=-1;for(i=1;i<len;i++){while(j>=0&&s[i]!=s[j+1])j=next[j];if(s[j+1]==s[i])j++;next[i]=j;}}int main(){int n;char str[MAX];int casenum=0;int i;int len;while(scanf("%d",&n)){casenum++;if(n==0)break;scanf("%s",str);len=strlen(str);printf("Test case #%d\n",casenum);calnext(str,next);for(i=1;i<len;i++){if((i+1)%(i-next[i])==0&&next[i]!=-1)printf("%d %d\n",i+1,(i+1)/(i-next[i]));}printf("\n");}return 0;}POJ 2752 Seek the Name, Seek the Fame这道题揭开了next的另一个应用^_^题目的意思可以这样描述:给出一个字符串S,长度为len;找出一个前缀一个后缀,使得这两个字符串相同。

输出所有可能的情况。

如aaaaa,aaaaa ——》OKaaaaa ——》OKaaaaa + aaaaa ——》OKaaaaa + aaaaa ——》OKaaaaa + aaaaa ——》OK那么这个题怎么用next呢,其实很简单,只要你知道next的含义。

合集下载

KMP算法详解

KMP算法详解
1
A = a b a b a b a a b a b … B = a b a b a c b j = 1 2 3 4 5 6 7 这时,新的 j=3仍然不能满足 A[i+1]=B[j+1],此时我们再次减小 j 值,将 j 再次更新为 P[3] ,即1: i = 1 2 3 4 5 6 7 8 9 …… A = a b a b a b a a b a b … B = a b a b a c b j = 1 2 3 4 5 6 7 现在,i 还是7,j 已经变成1了。而此时 A[8]居然仍然不等于 B[j+1]。这样,j 必须减小到 P[1],即0: i = 1 2 3 4 5 6 7 8 9 …… A = a b a b a b a a b a b … B = a b a b a c b j = 0 1 2 3 4 5 6 7 终于,A[8]=B[1],i 变为8,j 为1。事实上,有可能 j 到了0仍然不能满足 A[i+1]=B[j+1](比如 A[8]="d"时) 。 因此,准确的说法是,当 j=0了时,我们增加 i 值但忽略 j 直到出现 A[i]=B[1]为止。 这个过程的代码很短(真的很短) ,我们在这里给出: j:=0; for i:=1 to n do begin while (j>0) and (B[j+1]<>A[i]) do j:=P[j]; if B[j+1]=A[i] then j:=j+1; if j=m then begin writeln('Pattern occurs with shift ',i-m); j:=P[j]; end; end; 最后的 j:=P[j]是为了让程序继续做下去,因为我们有可能找到多处匹配。 这个程序或许比想像中的要简单,因为对于 i 值的不断增加,代码用的是 for 循环。因此,这个代码可以这 样形象地理解:扫描字符串 A,并更新可以匹配到 B 的什么位置。 现在,我们还遗留了两个重要的问题:一,为什么这个程序是线性的;二,如何快速预处理 P 数组。 为 什么这个程序是 O(n)的?其实,主要的争议在于,while 循环使得执行次数出现了不确定因素。我们将 用到时间复杂度的摊还分析中的主要策略,简单地说 就是通过观察某一个变量或函数值的变化来对零散的、杂 乱的、不规则的执行次数进行累计。KMP 的时间复杂度分析可谓摊还分析的典型。我们从上述程序的 j 值入手。 每一次执行 while 循环都会使 j 减小(但不能减成负的) ,而另外的改变 j 值的地方只有第五行。每次执行了这一 行,j 都只能加1;因此,整个过程 中 j 最多加了 n 个1。于是,j 最多只有 n 次减小的机会(j 值减小的次数当然 不能超过 n,因为 j 永远是非负整数) 。这告诉我们,while 循环总共最多执行 了 n 次。按照摊还分析的说法,平 摊到每次 for 循环中后,一次 for 循环的复杂度为 O(1)。整个过程显然是 O(n)的。这样的分析对于后面 P 数组预 处理 的过程同样有效,同样可以得到预处理过程的复杂度为 O(m)。 预处理不需要按照 P 的定义写成 O(m^2)甚至 O(m^3)的。我们可以通 过 P[1],P[2],...,P[j-1]的值来获得 P[j]的 值。对于刚才的 B="ababacb",假如我们已经求出了 P[1],P[2],P[3]和 P[4],看看我们应该怎么求出 P[5]和 P[6]。 P[4]=2,那么 P [5]显然等于 P[4]+1,因为由 P[4]可以知道,B[1,2]已经和 B[3,4]相等了,现在又有 B[3]=B[5],所 以 P[5]可以由 P[4] 后面加一个字符得到。P[6]也等于 P[5]+1吗?显然不是,因为 B[ P[5]+1 ]<>B[6]。那么,我们 要考虑“退一步”了。我们考虑 P[6]是否有可能由 P[5]的情况所包含的子串得到,即是否 P[6]=P[ P[5] ]+1。这里想 不通的话可以仔细看一下:

kmp 正则表达式

kmp 正则表达式

kmp 正则表达式摘要:1.KMP 算法简介2.KMP 算法与正则表达式的关系3.KMP 算法的应用场景4.KMP 算法的优缺点5.KMP 算法的实际应用案例正文:1.KMP 算法简介KMP(Knuth-Morris-Pratt)算法是一种高效的字符串匹配算法,用于在一个主字符串中查找一个子字符串出现的位置。

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

2.KMP 算法与正则表达式的关系正则表达式是一种强大的文本处理工具,可以用来检查字符串是否符合某种模式。

KMP 算法可以看作是一种特殊的正则表达式,因为它只在子字符串中进行匹配。

而正则表达式可以看作是KMP 算法的扩展,因为它可以处理更复杂的匹配需求。

3.KMP 算法的应用场景KMP 算法广泛应用于各种文本处理和数据分析任务中,例如:- 在搜索引擎中,KMP 算法可以帮助快速找到与用户查询关键词匹配的网页内容;- 在文本编辑器中,KMP 算法可以实现快速查找和替换功能;- 在生物信息学领域,KMP 算法可以用于基因序列比对和蛋白质序列比对等任务。

4.KMP 算法的优缺点KMP 算法的优点在于其高效性,通过预处理子字符串,可以避免大量不必要的字符比较,从而提高匹配速度。

然而,KMP 算法也存在一定的局限性,例如:- 如果子字符串过长或者出现频率较低,KMP 算法的性能提升可能不明显;- KMP 算法需要预处理子字符串,这可能会增加一定的计算负担。

5.KMP 算法的实际应用案例以搜索引擎为例,假设用户输入关键词“人工智能”,搜索引擎需要快速在海量的网页内容中找到包含该关键词的网页。

此时,KMP 算法可以帮助搜索引擎高效地进行字符串匹配,从而在短时间内返回与关键词匹配的网页内容。

KMP算法详解

KMP算法详解

KMP算法详解我们从一个普通的串的模式匹配算法开始讲起,这样你才能更深入的了解KMP算法及其优点。

咱们先来看看普通的串的模式匹配算法是怎么进行比较的主串(S) a b a b c a b c a c b a b子串(T)a b c a c (子串又被称为模式串)红色表示当前这趟比较指针所在位置,兰色表示当前这趟比较中匹配的部分第一趟(详细过程)a b a b c a b c a c b a ba b c a ca b a b c a b c a c b a ba b c a ca b a b c a b c a c b a ba b c a c遇到不匹配的地方时指针回朔,子串向前移动一位(下同),变成如下形式a b a b c a b c a c b a ba b c a c第二趟(省略了中间阶段指针移动比较过程,下同)a b a b c a b c a c b a ba b c a c第三趟a b a b c a b c a c b a ba b c a c第四趟a b a b c a b c a c b a ba b c a c第五趟aba b c a b c a c b a ba b c a c第六趟ab a b c a b c a c b a ba b c a c_完成匹配,跳出这就是普通算法的详细匹配过程,看明白了算法就简单了详细算法我现在就不给了,等以后有时间再编辑。

不过假如串的长度为m,子串的长度为n 的话,那么这个算法在最坏的情况下的时间复杂度为O(m*n) ,有没有办法降低它的时间复杂度呢?(废话,当然有拉,不然回这个帖子干什么)拜D.E.K nuth 和J.H.M orris 和V.R.P ratt 所赐,我们有了一种时间复杂度为O(m+n)的算法,为了纪念这3位强人为计算机科学所做的贡献,分别取这3位先生的名字的首写字母K,M,P来命名这个算法,即著名的KMP算法。

我们先不管这个KMP算法是什么,我们先来看看我们能够想到怎样的方法来改进上面的普通算法。

kmp算法最浅显理解 -回复

kmp算法最浅显理解 -回复

kmp算法最浅显理解-回复KMP算法最浅显理解KMP算法是一种高效的字符串匹配算法,它的核心思想是通过预处理来避免不必要的字符比较。

相较于朴素的字符串匹配算法,KMP算法的时间复杂度是线性的,具有较好的匹配性能。

在本文中,我们将逐步深入探讨KMP算法的原理、实现和应用。

1. 了解KMP算法的背景在讨论KMP算法之前,我们先了解一下字符串匹配问题的基本概念。

给定一个文本串T和一个模式串P,我们需要在T中找到P第一次出现的位置。

这个问题在实际应用中非常常见,比如在文本编辑器中查找某个关键字、在搜索引擎中对查询进行匹配等。

朴素的字符串匹配算法思路是从T 的每一个位置开始与P进行匹配,如果匹配失败则将T的位置向后移动一位继续匹配。

这种方法的时间复杂度是O(m*n),m和n分别为T和P的长度。

而KMP算法通过巧妙地利用已经匹配过的信息,将时间复杂度降低到O(m+n)的线性级别。

2. 理解KMP算法的原理KMP算法的核心是构建一个部分匹配表(partial match table),它记录了模式串中每一个位置的最长可匹配前缀后缀的长度。

具体来说,对于模式串P的每一个位置i(0≤i≤m-1),部分匹配表中的第i个元素记录的是P的前缀P[0:i]与后缀P[0:i]的最长公共部分的长度。

例如,如果P="ABCDABD",则部分匹配表为[0,0,0,0,1,2,0]。

这个表告诉我们,在字符"P[5]='B'"处匹配失败时,我们可以将模式串P向右移动2位,而不是从头开始重新匹配。

3. 如何构建部分匹配表构建部分匹配表需要遍历模式串P,并计算每个位置的最长可匹配前缀后缀的长度。

具体的算法如下:- 令next[0]=-1,i=0,j=-1;- 当i<m时,依次求解next[i];- 若j=-1或P[i]=P[j],则令i++,j++,并令next[i]=j;- 若P[i]!=P[j],则令j=next[j],直到找到满足条件的j或j=-1;- 返回next数组。

数据结构教学中KMP算法解析

数据结构教学中KMP算法解析

数据结构教学中KMP算法解析作者:张晓芳来源:《软件导刊》2013年第09期摘要:模式匹配是字符串的基本运算之一,也是数据结构教学中的难点之一。

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

关键词:数据结构;模式匹配;KMP算法中图分类号:G434 文献标识码:A 文章编号:16727800(2013)009019503作者简介:张晓芳(1970-),女,博士,华中科技大学网络与计算中心副教授,研究方向为数据库技术、数据挖掘。

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

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

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

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

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

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

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

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

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

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

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

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

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算法

KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配算法。

但是相较于其他模式匹配算法,该算法晦涩难懂,第一次接触该算法的读者往往会看得一头雾水,主要原因是KMP算法在构造跳转表next过程中进行了多个层面的优化和抽象,使得KMP算法进行模式匹配的原理显得不那么直白。

本文希望能够深入KMP算法,将该算法的各个细节彻底讲透,扫除读者对该算法的困扰。

KMP算法对于朴素匹配算法的改进是引入了一个跳转表next[]。

以模式字符串abcabcacab为例,其跳转表为:举例说明,如下是使用上例的模式串对目标串执行匹配的步骤next跳转表,在进行模式匹配,实现模式串向后移动的过程中,发挥了重要作用。

这个表看似神奇,实际从原理上讲并不复杂,对于模式串而言,其前缀字符串,有可能也是模式串中的非前缀子串,这个问题我称之为前缀包含问题。

以模式串abcabcacab为例,其前缀4 abca,正好也是模式串的一个子串abc(abca)cab,所以当目标串与模式串执行匹配的过程中,如果直到第8个字符才匹配失败,同时也意味着目标串当前字符之前的4个字符,与模式串的前4个字符是相同的,所以当模式串向后移动的时候,可以直接将模式串的第5个字符与当前字符对齐,执行比较,这样就实现了模式串一次性向前跳跃多个字符。

所以next表的关键就是解决模式串的前缀包含。

当然为了保证程序的正确性,对于next表的值,还有一些限制条件,后面会逐一说明。

如何以较小的代价计算KMP算法中所用到的跳转表next,是算法的核心问题。

这里我们引入一个概念f(j),其含义是,对于模式串的第j个字符pattern[j],f(j)是所有满足使pattern[1...k-1] = pattern[j-(k-1)...j - 1](k < j)成立的k的最大值。

(完整word版)KMP算法详解

KMP字符串模式匹配详解KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法。

简单匹配算法的时间复杂度为O(m*n);KMP匹配算法。

可以证明它的时间复杂度为O(m+n).。

一.简单匹配算法先来看一个简单匹配算法的函数:int Index_BF ( char S [ ], char T [ ], int pos ){/* 若串S 中从第pos(S 的下标0≤pos<StrLength(S))个字符起存在和串T 相同的子串,则称匹配成功,返回第一个这样的子串在串S 中的下标,否则返回-1 */int i = pos, j = 0;while ( S[i+j] != '\0'&& T[j] != '\0')if ( S[i+j] == T[j] )j ++; // 继续比较后一字符else{i ++; j = 0; // 重新开始新的一轮匹配}if ( T[j] == '\0')return i; // 匹配成功返回下标elsereturn -1; // 串S中(第pos个字符起)不存在和串T相同的子串} // Index_BF此算法的思想是直截了当的:将主串S中某个位置i起始的子串和模式串T相比较。

即从j=0 起比较S[i+j] 与T[j],若相等,则在主串S 中存在以i 为起始位置匹配成功的可能性,继续往后比较( j逐步增1 ),直至与T串中最后一个字符相等为止,否则改从S串的下一个字符起重新开始进行下一轮的"匹配",即将串T向后滑动一位,即i 增1,而j 退回至0,重新开始新一轮的匹配。

例如:在串S=”abcabcabdabba”中查找T=” abcabd”(我们可以假设从下标0开始):先是比较S[0]和T[0]是否相等,然后比较S[1] 和T[1]是否相等…我们发现一直比较到S[5] 和T[5]才不等。

KMP算法简析

KMP算法简析写在前⾯的话:KMP是个套娃算法,主串与⼦串匹配时,若S[i]==T[j] ,两个下标加加就完了;不相等,主串的下标不动,⼦串的下标跳转到前j个⼦串中最⼤重复部分的长度值处。

这个最⼤重复部分(准确的说是最长的相等的真前缀和真后缀)的长度怎么求呢?通过⼀个 next 数组来求得。

这个next数组的获得⼜是在⼦串中进⾏匹配,如果T[k]==T[j],next[j]=k, j、k 加加就完了,不相等的话不就⼜是回溯嘛?按照原来的⽅法,我们应该将k=0,然后重新⼀个⼀个⽐较寻找重复的⼦串。

但是我们有了next数组了,情况就不⼀样了。

直接让 k 回溯到前 k 个字符中最长重复部分(准确的说是最长的相等的真前缀和真后缀)长度所对应的下标不就好了吗?根据next 数组的含义,不就是next[k] 嘛?让k=next[k] 不就回去了吗纠结什么呢? 如果你是读者,看到这,你就不应该再看下去了。

除⾮你觉得我上⾯的有问题,可以在评论区骂我。

否则,如果你还是很懵,请到隔壁B站找个视频看看。

算法看博客,真不是个好主意。

⾸先,KMP算法是解决字符串匹配问题的算法,即在主串 S 中查找⼦串 T。

我们从问题⼊⼿,要在主串中查找⼦串,显然可以是⽤蛮⼒法逐个遍历,即从主串的第⼀个字符开始和⼦串的第⼀个字符⽐较,若相等则继续⽐较后续字符,若果不相等,则从主串的下⼀个的字符、⼦串的第⼀个字符重新开始⽐较。

如果在主串遍历完之后还没有找到对应⼦串,则匹配失败。

暴⼒法算法描述如下:public static int findSubString(String s,String t){int i = 0;int j = 0;// 标记主串中开始⽐较的字符下标int index = 0;//如果先主串完了就匹配不成功,⼦串先完了匹配成功。

两者都会结束循环while (i<s.length() && j<t.length()){//这个位置相等,继续下⼀个位置if (s.charAt(i) == t.charAt(j)) {i++;j++;}//这个位置不相等,则从主串的下⼀个字符、⼦串的第⼀个字符重新开始⽐较else{index++;i = index;j = 0;}}//循环结束,判断⼦串是否被匹配完了。

数据结构教学中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中的一个连续的字符序列相等,则称匹配成功,否则称匹配不成功。

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