kmp算法 next函数值推导过程和代码实现
KMP算法Next数组详解

KMP算法Next数组详解题⾯题⽬描述如题,给出两个字符串s1和s2,其中s2为s1的⼦串,求出s2在s1中所有出现的位置。
为了减少骗分的情况,接下来还要输出⼦串的前缀数组next。
如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习⼀下就知道了。
输⼊输出格式输⼊格式:第⼀⾏为⼀个字符串,即为s1(仅包含⼤写字母)第⼆⾏为⼀个字符串,即为s2(仅包含⼤写字母)输出格式:若⼲⾏,每⾏包含⼀个整数,表⽰s2在s1中出现的位置接下来1⾏,包括length(s2)个整数,表⽰前缀数组next[i]的值。
输⼊样例:ABABABCABA输出样例:130 0 1说明时空限制:1000ms,128M数据规模:设s1长度为N,s2长度为M对于30%的数据:N<=15,M<=5对于70%的数据:N<=10000,M<=100对于100%的数据:N<=1000000,M<=1000题解这是⼀道KMP裸题(模板题。
)我就是拿着它学习⼀下KMP算法其实原来我学过KMP算法但是⼀直没有弄懂next(跳转)数组是如何求出来的。
最近花了⼀个下午⾃⼰研究了⼀下KMP算法现在终于觉得KMP很简单了~现在直接说next数组把⾄于有什么作⽤,next数组是⼲什么的,请⾃⾏百度,有很多dalao总结的⾮常到位,看⼀看就会明⽩。
好,来说next数组并不⽤在意这⼀坨⿊的是什么东西,我们就假设他是我们要求next数组的字符串。
next数组求的东西就是从起始位置到当前位置最长的相等的前缀和后缀的长度。
(举个例⼦China的前缀有:C、Ch、Chi、Chin、China ;后缀有a、na、ina、hina、China)我们继续,如上图红⾊的是当前位置(设为j)前,所匹配上的最长前缀和后缀,蓝⾊的是当前要匹配的位置。
那么,我们就拿当前位置和原来匹配到的最长前缀的后⼀位相⽐较如果两个位置相同,显然,可以和前⾯的红⾊连在⼀起,此时就有next[j]=next[j-1]+1如果两个位置不相同,根据next数组的性质,显然的,你的当前的相等的前缀和后缀只能够继续向前找,也就是说,你当前的next数组⼀定会减⼩。
kmp算法 公式

KMP算法是一种字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。
它的核心思想是利用已经匹配过的部分信息,尽量减少不必要的比较。
KMP算法的公式如下:1. 预处理模式串,得到next数组:-初始化next数组,next[0] = -1,next[1] = 0;-从第2个字符开始,依次计算next[i]的值:-如果模式串的前缀和后缀匹配,即pattern[j] == pattern[i-1],则next[i] = j + 1;-如果模式串的前缀和后缀不匹配,即pattern[j] != pattern[i-1],则需要回溯到前一个可能的匹配位置,即j = next[j],直到找到一个匹配位置或者回溯到起始位置;-如果回溯到起始位置仍然没有找到匹配位置,则next[i] = 0。
2. 在主串中查找模式串:-初始化主串指针i = 0,模式串指针j = 0;-依次比较主串和模式串的字符:-如果主串和模式串的字符匹配,即text[i] == pattern[j],则继续比较下一个字符;-如果主串和模式串的字符不匹配,即text[i] != pattern[j],则需要根据next数组回溯模式串的指针j,即j = next[j],直到找到一个匹配位置或者回溯到起始位置;-如果回溯到起始位置仍然没有找到匹配位置,则主串指针i和模式串指针j都向后移动一位,继续比较下一个字符;-如果模式串指针j移动到模式串的末尾,则表示找到了一个匹配位置,返回匹配位置的起始索引;-如果主串指针i移动到主串的末尾,则表示没有找到匹配位置,返回-1。
KMP算法通过预处理模式串得到next数组,利用next数组的信息在匹配过程中尽量减少不必要的比较,提高了匹配效率。
数据结构(三)串---KMP模式匹配算法之获取next数组

数据结构(三)串---KMP模式匹配算法之获取next数组⽬录(⼀)获取模式串T的next数组值1.我们所知道的KMP算法next数组的作⽤next[j]表⽰当前模式串T的j下标对⽬标串S的i值失配时,我们应该使⽤模式串的下标为next[j]接着去和⽬标串失配的i值进⾏匹配⽽KMP算法的next求值函数我们可以知道next除了j=1时,next[1]为0,其他情况都是⽐较前缀和后缀串的相似度(第三种情况是当相似度为0时,next值为0+1=1)next数组,是⽤来评判前后缀的相识度,⽽next值,则是等于相似度加⼀2.虽然我们知道是⽐较前后缀的相似度,但是我们如何确定前后缀位置来获取next值。
---->pj的next值取决于前缀p1p2....pk-1 后缀pj-k+1.....pj-1 的相似度,next值是相似度加⼀pj的next值取决于前缀p1p2....pk-1 后缀pj-k+1.....pj-1的相似度,是相似度加⼀。
我们将k-1=m,其中m就是相似度,k就是next数组值-->Max{K}pj的next值取决于前缀p1p2....pm 后缀pj-m.....pj-1 的相似度,是相似度加⼀。
那么我们现在的任务,就由找k-1变为找m,找相似度例如:虽然我们可以直接看出abab的相似度是2,也可以编写函数获取到其相似度,⽽且当我们求下⼀个next值时,串变为ababa,这时我们也可以看出相似度为3,使⽤同⼀个函数可以实现获取到相似度。
但是我们这个函数⼤概就是从头或尾开始索引,进⾏判断。
每次我们获取到了⼦串都要交给这个函数从头到尾去索引获取相似度,似乎不划算,我们是不是应该有更好的⽅法增加程序的性能?3.下⾯我们尝试获取下⾯的T串的所有next值,从中找到关联步骤⼀:由上⼀篇博⽂可以知道前j1,j2前两个的next是固定值为0,步骤⼆:获取j=3时的next,此时⼦串只有'ab',所以⼦串的前缀只能选择'a',后缀只能选择'b';下⾯我们对前后缀进⾏匹配next数组,是⽤来评判前后缀的相识度,⽽next值,则是等于相似度加⼀next[j]表⽰当前模式串T的j下标对⽬标串S的i值失配时,我们应该使⽤模式串的下标为next[j]接着去和⽬标串失配的i值进⾏匹配注意:匹配完毕后后缀会向下加⼀步骤三:获取j=4时的next值,此时⼦串为'aba',⼦串中前缀是p1..pm,后缀是pm+1..pj-1,若是m取⼀,此时⼦串的前缀可以选择p1,后缀选择p2;若是m=2前缀选择p1p2后缀选择p2p3;那么具体如何选择这个m值呢?重点:这个m值取决于上次失配时的next[]值,即上次j=3是失配了,所有m=next[3]=1,所以我们选取的前缀为p1='a',后缀为pj-1是'a'根据匹配处的相似度或者下标J=1都可以得出next[4]=2步骤四:获取j=5时的next值,此时⼦串为'abab',⼦串中前缀是p1..pm,后缀是pm+1..pj-1,若是m取⼀,此时⼦串的前缀可以选择p1,后缀选择p2;若是m=2前缀选择p1p2后缀选择p2p3,若m取3,前缀为p1p2p3后缀为p2p3p4;那么具体如何选择这个m值呢?重点:若是上次匹配成功。
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算法模板及理解

kmp算法模板及理解kmp算法是复杂度为O(n+m)的字符串匹配算法;⾸先kmp算法的核⼼是在模式串中获得next数组,这个数组表⽰模式串的⼦串的前缀和后缀相同的最长长度;这样在匹配的过程中如果指到不匹配的位置,模式串⽤next数组进⾏跳转到符合的位置,⽽⽬标串不需要再往回匹配,为什么是最长的相同的前缀后后缀呢?因为只有这样才能⼀边避免可能漏掉的位置,⼀边尽量不重复已经匹配的位置;getNext的函数:void getNext(){int k = -1,j = 0,len = strlen(str);next[0] = -1;while(j < len){if(k == -1||str[j] == str[k]){j++;k++;next[j] = k;//相等的话就往后继续;}else k = next[k];//不等的话就相当于kmp⼀样,把模式串的这个⼦串⽤已经求出来的next跳转;}}kmp算法代码:int kmp(){int posP = 0,posT = 0;int lenP = strlen(strP),lenT = strlen(strT);while(posP < lenP&&posT < lenT){if(posP == -1||strP[posP] == strT[posT]){posP++;posT++;}else posP = next[posP];if(posP == lenP)return posT-lenP;//匹配成功返回匹配成功的位置;}return -1;//匹配失败哦;}。
kmp算法程序 exerise 5

实验5: KMP算法1.熟悉字符串的使用。
2.掌握Index算法,kmp算法应用到模式匹配。
二、实验内容求出子串(模式串)的next值,利用kmp算法实现子串与主串的匹配。
实现Index算法,并与KMP进行性能比较。
三、实验步骤1.生成模式串的next函数2.从第1个字符开始,进行模式串与主串的比较,3.如果出现失配,将模式串的第next[j]位置开始,继续与主串进行比较。
源程序及结果:#include<stdio.h>#include<string.h>void get_nextval(char T[],int next[]){int i = 1;int j = 0;next[1] = 0;while (i<strlen(T)){if (j==0 || T[i]==T[j]){++i;++j;if (T[i]!=T[j])next[i] = j;elsenext[i] = next[j];}elsej = next[j];}}void Index_KMP(char S[], char T[], int & pos1, int & a) {int next[10];int i=1,j=1, p,a=0;int n=strlen(S)-1;int m=strlen(T)-1;get_nextval(T, next);for(p=1;p<10;p++){printf("%d",next[p]);}printf("\n");while(i<=n&&j<=m){if(j!=0)a++;if (j==0||S[i]==T[j]){++i;++j;}elsej = next[j];}if (j>m)pos1=i-m;elsepos1=0;}void Index(char S[], char T[], int & pos2,int & b){int i=1,j=1,b=0;int m,n;m=strlen(S)-1;n=strlen(T)-1;while(i<=m&&j<=n){ b++;if(S[i]==T[j]){++i;++j;}else{i=i-j+2;j=1;}}if(j>n)pos2=i-n;elsepos2=0;}void main(){char s[100];char t[10];int next[10];int pos1;int pos2;int a;int b;while(1){ printf("请输入主串:");scanf("%s",s);printf("请输入子串:");scanf("%s",t);Index_KMP(s,t,pos1,a);printf("KMP 算法,匹配位置pos1 %d,次数:%5d\n",pos1,a);Index(s,t,pos2,b);printf("Index 算法,匹配位置pos2 %d,次数:%5d\n",pos2,b);}}。
扩展kmp算法
扩展kmp算法扩展KMP算法什么是扩展KMP?扩展kmp是求模式串和主串的每个后缀的最长公共前缀长度。
扩展KMP算法是利⽤前⾯的已知条件降低多余匹配,达到缩短时间的算法。
扩展KMP算法⽬的是得到next数组和extend数组。
next[ i ] 表⽰的是从⾃⼰的第i位開始。
模式串T与⾃⼰匹配的字符个数。
extend[ i ] 表⽰的是从主串S的第i位開始,模式串T与主串S匹配的字符个数。
扩展KMP算法的思路:先介绍⼏个⽐較重要的參数:a:当前求next值或者extend值时使得p最⼤时的位置。
p:当前⽐較过的最⼤位置。
p=a+next[ a ]-1或者p=a+extend [ a ]-1。
这个式⼦不难理解吧。
l:是利⽤模式串T的⾃相似性求出的当前第i位的的最长公共前缀长度,可是并不⼀定等于实际的最长公共前缀长度。
这仅仅是依据已经匹配过得数据得出的结论。
后没有匹配过得地⽅谁也说不定。
或许没匹配过得地⽅也同样呢。
也就是说extend[ i ]>=l。
或者next[ i ]>=l。
l=next[ i-a ]。
注意不管是求next 还是extend 都是同⼀个式⼦。
求next数组:next [ 0 ]等于字符串T的长度。
通过逐个⽐較的⽅法求出next [ 1 ]。
然后逐个求第2~n的next值。
推断l+i-1>=p是否成⽴。
即推断通过模式串⾃相似性求出的最长公共⼦串是否超过已经⽐較过的最⼤位置。
若成⽴,继续向后⽅没有⽐較过的位置⽐較。
若匹配⾃加1,直到不匹配为⽌此时的值即为next[ i ]的值。
若不成⽴,next [ i ]=l 。
求extend数组:通过逐个⽐較求出extend[ 0 ]。
然后逐个求第1~n的extend值。
推断l+i-1>=p是否成⽴。
即推断通过模式串⾃相似性求出的最长公共⼦串是否超过已经⽐較过的最⼤位置。
若成⽴。
继续向后⽅没有⽐較过的位置⽐較。
若匹配⾃加1,直到不匹配为⽌此时的值即为extend[ i ]的值。
kmp算法next计算方法
kmp算法next计算方法KMP算法是一种字符串匹配算法,它的核心在于利用已经部分匹配的信息来减少匹配的次数,从而提高匹配的效率。
在KMP算法中,next数组的计算是非常关键的一步,它可以帮助我们快速地找到匹配失败时,模式串应该向后移动的位置。
本文将详细介绍KMP算法中next数组的计算方法。
首先,我们先来了解一下next数组的含义。
在KMP算法中,next数组的含义是指在模式串中,每个位置上对应的最长公共前缀和最长公共后缀的长度。
这个定义可能有点抽象,我们通过一个具体的例子来说明。
假设模式串为"ABCDABD",那么它的next数组为[-1, 0, 0, 0, 0, 1, 2]。
这里的-1表示第一个字符没有前缀和后缀,0表示第二个字符A的前缀和后缀的长度为0,以此类推,最后一个字符D的前缀和后缀的最大长度为2。
接下来,我们来介绍如何计算next数组。
计算next数组的方法有两种,一种是暴力匹配法,另一种是利用已知的next数组来计算。
暴力匹配法的思路是,对于模式串的每个位置i,都尝试找到它的最长公共前缀和最长公共后缀的长度。
这种方法的时间复杂度为O(n^2),其中n为模式串的长度,显然效率不高。
而利用已知的next数组来计算的方法则更加高效。
具体步骤如下:1. 首先,我们将next数组初始化为-1,即next[0]=-1。
2. 然后,我们从模式串的第一个字符开始,依次计算每个位置上的next值。
3. 在计算位置i的next值时,我们首先假设位置i的前一个字符的next值已知,记为k,即next[i-1]=k。
4. 如果模式串的第k个字符和第i-1个字符相等,那么位置i的next值为k+1;否则,我们继续向前寻找更短的公共前缀和后缀,直到找到一个满足条件的k值或者k等于-1为止。
通过这种方法,我们可以高效地计算出整个模式串的next数组。
这样,在实际的匹配过程中,当发生匹配失败时,我们就可以根据next数组来快速地确定模式串应该向后移动的位置,从而提高匹配的效率。
字符串匹配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)KMP算法是一种字符串匹配算法,可用于在一个较长的文本串中寻找一个较短的模式串出现的位置。
它的核心思想是利用已匹配的部分信息来避免不必要的字符比较,从而提高匹配效率。
KMP算法的实现主要有两种方法,分别是暴力匹配和使用next数组。
一、暴力匹配方法:暴力匹配方法是KMP算法的基础,也是最简单直接的实现方式。
它的思想是通过两个指针i和j分别指向文本串和模式串,按照顺序比较它们的每个字符,如果当前字符匹配成功,则继续比较下一个字符,直到完全匹配或者不匹配。
具体实现步骤如下:1.初始化两个指针i和j,分别指向文本串和模式串的起始位置。
2.循环比较两个指针所指的字符,如果相同则同时向后移动,如果不同则i回退到起始位置的下一位,j回退到起始位置。
3.重复第2步,直到模式串完全匹配或者文本串遍历完。
4.如果模式串完全匹配,则找到了匹配的位置,否则未找到匹配。
暴力匹配的时间复杂度是O(m*n),其中m是模式串的长度,n是文本串的长度。
虽然简单易懂,但对于大规模的文本串效率较低。
二、使用next数组方法:使用next数组是KMP算法的优化方式,通过构建next数组可以避免不必要的字符比较,提高匹配的效率。
具体实现步骤如下:1. 根据模式串构建next数组,next[i]表示从模式串起始位置到第i个字符的子串的最长相同前后缀长度。
- 如果模式串的第i个字符和第j个字符不相等,则next[i] = j (j为前一个字符的最长相同前后缀长度)- 如果模式串的第i个字符和第j个字符相等,则next[i] =next[j] (即前一个字符的最长相同前后缀长度+1)2.初始化两个指针i和j,分别指向文本串和模式串的起始位置。
3. 循环比较两个指针所指的字符,如果相同则同时向后移动,如果不同则j回退到next[j]的位置。
4.重复第3步,直到模式串完全匹配或者文本串遍历完。
5.如果模式串完全匹配,则找到了匹配的位置,否则未找到匹配。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
KMP算法(Knuth-Morris-Pratt算法)是一种改进的字符串匹配算法,它通过预处理模式字符串来减少比较次数,从而提高匹配效率。
其中,next函数是KMP算法中的重要组成部分,用于计算模式字符串中每个位置对应的最大前后缀长度。
next函数的推导过程如下:
设模式字符串为P,P的长度为n。
对于P中的每个位置i(0 <= i < n),若P[i]与P[j]相等,则称j为i的前缀。
若j是i的前缀,且P[j+1]...P[i-1]也是i的前缀,则称j为i的回溯前缀。
next函数返回的是每个位置i的回溯前缀的最大值。
例如,对于模式字符串P="ABABAC",P的每个位置的回溯前缀如下:
A: 0(无回溯前缀)
B: 0(无回溯前缀)
A: 0(无回溯前缀)
B: 0(无回溯前缀)
A: 1(回溯前缀为"A")
B: 2(回溯前缀为"AB")
A: 2(回溯前缀为"AB")
C: 3(回溯前缀为"ABC")
因此,对于模式字符串P="ABABAC",next数组为[0, 0, 0, 0, 1, 2, 2, 3]。
下面是next函数的Python实现:
def next(pattern):
n = len(pattern)
next = [0] * n
length = [0] * n
j = 0 # j表示当前位置i的前缀的最大长度
for i in range(1, n):
while j > 0 and pattern[i] != pattern[j]:
j = length[j-1]
if pattern[i] == pattern[j]:
j += 1
length[i] = j
return next。
希望以上信息能帮助到你。