KMP算法详解课件

合集下载

KMP算法(原创)PPT教学课件

KMP算法(原创)PPT教学课件

? 这时如何求next[j+1]呢
2020/12/10
11
转化法
式1的结论可这样描述:何时的k使得
pk=pj,就用此时的k代入式1。
而现在的k是pk!=pj,因此必须要换成另外 一个“k”,并设它为k2,以使得pk2=pj。
问题又出来了: k2如何得来?
如图: 0 j-k+1
j
P’
2/10
2
(2) Brute-Force算法的实现
int String::Find Substr(const String& t, int start)const {
int i = start, j = 0, v; while(i < size && j < t.size) {
if(str[i] == t.str[j]) {i++;j++;} else {i = i-j+1;j = 0;} } if(j >= t.size-1) v = i-t.size+1; else v = -1; return v; }
由(1)(2)两式便可得:
‘p0p1……pk-1’= ‘pj-kpj-k+1……pj-1’ (3) (3)式的结论可如下描述:
在模式p中,前k个字符与第j个字符之前 的k个字符相同。
2020/12/10
7
设next[j]表示:当模式中第j个字符与正 文中相应字符“失配”时,在模式中重 新和正文中该字符进行比较的字符的位 置。
利用next数组进行模式匹配示例:
2020/12/10
9
如何预先求得next数组值
首先要明确一点: next数组的求值只与 模式p有关,而与具体的正文s无关。

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讲解
2.2、kmp算法
有了覆盖函数,那么实现kmp算法就是很简单的了,我们的原则还是从左向右匹配,但是当失配发生时,我们不用把target_index向回移动,target_index前面已经匹配过的部分在pattern自身就能体现出来,只要动pattern_index就可以了。
当发生在j长度失配时,只要把pattern向右移动j-overlay(j)长度就可以了。
说了这么半天那么这种方法是什么呢,这种方法是就大名鼎鼎的确定的有限自动机(Deterministic finite state automaton DFA),DFA可识别的文法是3型文法,又叫正规文法或是正则文法,既然可以识别正则文法,那么识别确定的字串肯定不是问题(确定字串是正则式的一个子集)。对于如何构造DFA,是有一个完整的算法,这里不做介绍了。在识别确定的字串时使用DFA实在是大材小用,DFA可以识别更加通用的正则表达式,而用通用的构建DFA的方法来识别确定的字串,那这个overhead就显得太大了。
{
index = overlay_value[index];
}
if(pattern[index+1]==pattern[i])
{
overlay_value[i] = index +1;
KMP 算法可在O(n+m)时间内完成全部的串的模式匹配工作。
ok,最后给出KMP算法实现的c++代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
int kmp_find(const string& target,const string& pattern)

实验04:串应用KMP算法PPT课件

实验04:串应用KMP算法PPT课件

在生物信息学中的应用
在生物信息学中,KMP算法被广泛应用于基因序列的比对和拼接,以及蛋白质序列 的匹配和比对。
通过构建基因序列或蛋白质序列的索引表,KMP算法可以在O(n+m)的时间复杂度 内完成序列的比对和拼接,提高了比对和拼接的准确性和效率。
KMP算法在生物信息学中的应用有助于深入了解基因和蛋白质的结构和功能,为生 物医学研究和疾病诊断提供了有力支持。
06 实验总结与展望
KMP算法的优缺点
优点
高效:KMP算法在匹配失败时能跳过 尽可能多的字符,减少比较次数,从
而提高匹配效率。
适用范围广:KMP算法适用于各种模 式串匹配问题,不受模式串长度的限 制。
缺点
计算量大:KMP算法需要计算和存储 部分匹配表,对于较长的模式串,计 算量较大。
不适合处理大量数据:KMP算法在处 理大量数据时可能会占用较多内存, 导致性能下降。
匹配失败的处理
当模式串中的某个字符与主串中的对应字符不匹配时,模式串向右 滑动,与主串的下一个字符重新对齐,继续比较
next[ j]表示当模式串中第j个字符与主 串中的对应字符不匹配时,模式串需 要向右滑动的位置。
next数组的构建
next数组的作用
在匹配过程中,通过next数组可以快 速确定模式串需要滑动到哪个位置, 从而提高了匹配效率。
通过已知的next值,递推计算出next 数组中其他位置的值。
KMP算法的时间复杂度
01
02
03
04
时间复杂度分析
KMP算法的时间复杂度取决 于模式串在主串中出现的次数 以及每次匹配所花费的时间。
最佳情况
当模式串在主串中连续出现时 ,KMP算法的时间复杂度为

kmp算法课件演示推荐

kmp算法课件演示推荐

kmp算法课件演示(推荐)2007-10-12 22:23:51 阅读625 评论1 字号:大中小订阅(1)以一个例子引入KMP算法先看朴素模式匹配过程:(a)S:a b b a b a= = ≠P:a b a0 1 2(b)P3≠S3,P右移一位S:a b b a b a(c) P1≠S2,P右移一位S:a b b a b a≠P:a b a(d) P1≠S3,P右移一位S:a b b a b a= = =P: a b a(e)匹配成功index(S,P)=4, substr(S,4,3)=P从匹配过程看:首先在(a)中p1=s1,p2=s2,p3≠s3,只需将模式右移到s3,不需将主串回溯到s2;其次,由于p1≠p2,可推出p1≠s2,做(b)的比较一定不等;再由p1=p3,可以推出p1≠s3,做(c)的比较也一定不等。

因此,由(a)便可直接将P右移三位跳到(d),从p1和t4开始进行比较,这样的匹配过程对S(主串)而言就消除了回溯。

为要找到一个无回溯的匹配算法,关键在于当匹配过程中,一旦p j和s i比较不等,存在:substr(p,1,j-1)=substr(s,i-j+1,j-1)p j≠s i改进的模式匹配算法的思想:在匹配过程中,当主串第i个字符与模式串第j个字符“失配”时,要产生模式串右移的位数和继续与主串(主串无回溯的)比较的字符,即应该用P中哪个字符和S i进行比较?把这个字符记为P k,显然有k<j,并且对不同的j,k值也不相同。

这个k 值仅依赖于模式P本身前j个字符的构成,而与目标S无关。

一般用next[j]表示与j对应的k值,表明当模式中第j个字符与主串中第i个字符“失配”时,在模式中需重新和主串中第i字符进行比较的字符的位置。

s1 s2……………..s i-k+1……..s i-1 s i s i+1……s np1p2……p k-1 p k.p j-k+1 …………p j-1 p j p j+1…..p m 假设此时应与模式串中第k个字符继续比较,则模式中前k-1个字符的子串必须满足下列关系:“p1p2…p k-1”=“s i-k+1s i-k+2…s i-1”由部分匹配知:“p j-k+1p j-k+2…p j-1”=“s i-k+1s i-k+2…s i-1”推得:“p1p2…p k-1”= “p j-k+1p j-k+2…p j-10 当j=1时next[j]=Max{k|1<k<j且“p1p2…p k-1”=“p j-k+1p j-k+2…p j-1”1 其它情况abcac01112例: i=3第一趟匹配 a b a b c a b c a c b a ba b c a c↑j=3 next[3]=1↓i —→↓i=7第二趟匹配 a b a b c a b c a c b a ba b c a c↑—→↑j=5 next[5]=2j=1↓i —→↓i=10第三趟匹配 a b a b c a b c a c b a ba b c a c↑j=2其意义在于:若next[j]>0表示一旦匹配过程中P i 与S i比较不等,可用模式中next[j]为下标的字符与S i 进行比较;若next[j]=0表示P中任何字符都不必再与S i 进行比较,而从S i+1开始。

kmptrieACPPT课件

kmptrieACPPT课件
(4)
kmp
由此,串的模式匹配重点构造模式串t构 造回溯的next数组,用于记录匹配失败 后模式串回溯的位置
为了加速找next数组,可以采用压缩路 径的方式next[i]=next[j] (具体写法要根 据题目需求)
kmp
void getNext(){
next[0]=-1; //next数组0-n,包括n
Kmp_trie_AC自动机
kmp
什么是子串:
对于一个字符串变量,例如“adereegfbw”,它的子串就 是像“ader”这样可以从中找到的连续的字符串。
字符串“adereegfbw”本身也属于它本身最长的子串。 子串计算方法: ab的子串:a、b、ab共3个即(2+1
)个,abc的子串:a、 b、 c、 ab、 bc、abc 共( 3+2+1)个, 所以若字符串的长度为n,则子串的个数 就是[n+(n-1)+.......+1]个,"software"中非空子串的 个数就是8+7+....+1=36个, 如果包括空串,则应为37 个。
字符串,让你在矩阵里找出这个字符串,如果存在, 输出第一个字符位置以及方向 (A-H从北开始顺时针八 个方向) )
解法:对字符串构造trie树,然后枚举矩阵里每个点及 八个方向,走一趟trie树,判断是否在trie上有cnt
AC自动机
AC自动机可以说是kmp与trie树的结合 利用trie树的树形结构,在trie树上构造
AC自动机
AC自动机
匹配过程分两种情况:(1)当前字符匹配 ,表示从当前节点沿着树边有一条路径 可以到达目标字符,此时只需沿该路径 走向下一个节点继续匹配即可,目标字 符串指针移向下个字符继续匹配;(2)当 前字符不匹配,则去当前节点失败指针 所指向的字符继续匹配,匹配过程随着 指针指向root结束。重复这2个过程中的 任意一个,直到模式串走到结尾为止。

KMP算法详解

KMP算法详解

KMP算法详解(C++版)KMP算法是一种字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法).KMP 算法之所以难懂,很大一部分原因是很多实现的方法在一些细节的差异。

然后去看另外的方法,就全都乱了!体现在几个方面: next 数组,有的叫做“失配函数”,其实是一个东西; next 数组中,有的是以下标为 0 开始的,有的是以 1 开始的; KMP 主算法中,当发生失配时,取的 next数组的值也不一样!就这样,各说各的,乱的很!所以,在阐述我的理解之前,我有必要说明一下,我是用 next 数组的, next 数组是以下标 0 开始的!还有,我不会在一些基础的概念上浪费太多,所以你在看这篇文章时必须要懂得一些基本的概念,例如“朴素字符串匹配”“前缀”,“后缀”等!假设在我们的匹配过程中出现了这一种情况:根据 KMP 算法,在该失配位会调用该位的 next 数组的值!在这里有必要来说一下 next 数组的作用!说的太繁琐怕你听不懂,让我用一句话来说明:返回失配位之前的最长公共前后缀!好,不管你懂不懂这句话,我下面的文字和图应该会让你懂这句话的意思以及作用的!首先,我们取之前已经匹配的部分(即蓝色的那部分!)我们在上面说到 next 数组的作用时,说到“最长公共前后缀”,体现到图中就是这个样子!接下来,就是最重要的了!没错,这个就是 next 数组的作用了 :返回当前的最长公共前后缀长度,假设为 len 。

因为数组是由 0 开始的,所以 next 数组让第 len位与主串匹配就是拿最长前缀之后的第 1 位与失配位重新匹配,避免匹配串从头开始!如下图所示!(重新匹配刚才的失配位!)如果都说成这样你都不明白,那么你真的得重新理解什么是 KMP 算法了!接下来最重要的,也是 KMP 算法的核心所在,就是 next 数组的求解!不过,在这里我找到了一个全新的理解方法!如果你懂的上面我写的的,那么下面的内容你只需稍微思考一下就行了!跟刚才一样,我用一句话来阐述一下 next 数组的求解方法,其实也就是两个字:继承a 、当前面字符的前一个字符的对称程度为 0 的时候,只要将当前字符与子串第一个字符进行比较。

小学信息课件:-第2章 KMP算法

小学信息课件:-第2章  KMP算法

·P[5]=3是因为B[1…3]和B[3…5]都是aba;而P[3]=1则告诉我 们,B[1],B[3]都是a 。既然P[6]不能由P[5]=3得到,或许可以 由P[3]=1得到(如果B[2]恰好和B[6]相等的话,P[6]就等于2 了)。显然,P[6]也不能通过P[3]=1得到,因为B[2]≠B[6]。 事实上,这样一直推到P[1]也不行,最后,我们得到P[6]=0。 ·代码和主程序神似,实际上就是B串“自我匹配”的过程。 1.P[1] = 0; 2.j = 0; 3.for (int i = 2; i <= m; ++i) { 4. while (j > 0 && B[j + 1] != B[i]) j = P[j]; 5. //不能继续匹配且j还没减到0,考虑退一步 6. if (B[j + 1] == B[i]) ++j; //能匹配,j的值+1 7. P[i] = j; 8.}
KMP算法
by cx
介绍
·KMP算法用来处理字符串匹配问题,也就是问某个字符串B 是否是字符串A的子串。
·解决这类问题,通常我们的方法是枚举从A串的什么位置起 开始与B匹配,然后验证是否匹配。假如A串长度为n,B串长 度为m,那么这种方法的最坏复杂度是O(nm)的。
·我们将介绍的是一种最坏情况下O(n)的算法,即KMP算法。
·事实上,有可能j=0时仍然不满足 A[i+1]≠B[j+1] 。
·因此当j=0时,我们增加i值但忽略j直到出现A[i]=B[1]
为止。
·代码实现
1.j = 0;

2.for(int i = 1; i <= n; ++i) {

KMP演示

KMP演示

c a b c a c b a b
c a b c a c b a b c a c c a b c a c b a b
c a b c a c b a b a 第六趟匹配 a b a b c a b c a c b a b a b c a c
简单匹配算法的复杂度分析

设n = StrLength(S);m = StrLength(T); 最好情况的复杂度为O(n+m),如
简单匹配算法的匹配过程示例

例如 T=“abcac”; S=“ababcabcacbab”
• • • • • • • • • • • • 第一趟匹配 a b a b a b c 第二趟匹配 a b a b a 第三趟匹配 a b a b a b 第四趟匹配 a b a b a 第五趟匹配 a b a b c a b c a c b a b (i=3) (j=3) (i=2) (j=1) (i=7) (j=5) (i=4) (j=1) (i=5) (j=1) (i=11) (j=6) 成功!

• 并且不可能存在 k’>k 使上述关系成立. • 这就是说 next[j+1]=k+1 或 next[j+1]=next[j]+1

(2)若tk tj,则表明:“” “tj-k+1...tj”
• 此时求next的问题可看成模式匹配的问题; • 递推 k=next[k],直到T[k]=T[j]或k=0; • 此时 next[j+1]=next[k]+1




BEGIN assign(input,'kmp.in');reset(input); assign(output,'kmp.out');rewrite(output); Readln(str_s); Readln(str_t); int_i := index( str_s, str_t ); if int_i <> 0 then begin Writeln(int_i); end else Writeln('Cannot find!' ); END.

KMP算法详解

KMP算法详解

KMP算法思想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算法

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算法详解bymatrix67

kmp算法详解bymatrix67

KMP算法详解如果机房马上要关门了,或者你急着要和MM约会,请直接跳到第六个自然段。

我们这里说的KMP不是拿来放电影的(虽然我很喜欢这个软件),而是一种算法。

KMP算法是拿来处理字符串匹配的。

换句话说,给你两个字符串,你需要回答,B串是否是A串的子串(A串是否包含B串)。

比如,字符串A="I'm matrix67",字符串B="matrix",我们就说B是A的子串。

你可以委婉地问你的MM:“假如你要向你喜欢的人表白的话,我的名字是你的告白语中的子串吗?”解决这类问题,通常我们的方法是枚举从A串的什么位置起开始与B匹配,然后验证是否匹配。

假如A串长度为n,B串长度为m,那么这种方法的复杂度是O (mn)的。

虽然很多时候复杂度达不到mn(验证时只看头一两个字母就发现不匹配了),但我们有许多“最坏情况”,比如,A= "aaaaaaaaaaaaaaaaaaaaaaaaaab",B="aaaaaaaab"。

我们将介绍的是一种最坏情况下O(n)的算法(这里假设m<=n),即传说中的KMP算法。

之所以叫做KMP,是因为这个算法是由Knuth、Morris、Pratt三个提出来的,取了这三个人的名字的头一个字母。

这时,或许你突然明白了A VL 树为什么叫A VL,或者Bellman-Ford为什么中间是一杠不是一个点。

有时一个东西有七八个人研究过,那怎么命名呢?通常这个东西干脆就不用人名字命名了,免得发生争议,比如“3x+1问题”。

扯远了。

个人认为KMP是最没有必要讲的东西,因为这个东西网上能找到很多资料。

但网上的讲法基本上都涉及到“移动(shift)”、“Next函数”等概念,这非常容易产生误解(至少一年半前我看这些资料学习KMP时就没搞清楚)。

在这里,我换一种方法来解释KMP算法。

假如,A="abababaababacb",B="ababacb",我们来看看KMP 是怎么工作的。

数据结构课件-KMP算法样例20160926

数据结构课件-KMP算法样例20160926

(未优化)(1)Next[0]=-1 => i=0, j=-1 => i++, j++ => i=1, j=0 => Next[i]=j, Next[1]=0(2)i=1, j=0 => j>-1&&p[1]!=p[0] => j=Next[0]=-1 => i++, j++ => i=2, j=0 => Next[i]=j,Next[2]=0(3)i=2, j=0 => j>-1&&p[2]==p[0] => i++, j++ => i=3, j=1 => Next[i]=j, Next[3]=1(4)i=3, j=1 => j>-1&&p[3]!=p[1] => j=Next[1]=0 => j>-1&&p[3]!=p[0] => j=Next[0]=-1=> i++, j++ => i=4, j=0 => Next[i]=j, Next[4]=0(5)i=4, j=0 => j>-1&&p[4]==p[0] => i++, j++ => i=5, j=1 => Next[i]=j, Next[5]=1(带优化)(1)Next[0]=-1 => i=0, j=-1 => i++, j++ => i=1, j=0 => p[i]!=p[j], p[1]!=p[0] => Next[i]=j,Next[1]=0(2)i=1, j=0 => j>-1&&p[1]!=p[0] => j=Next[0]=-1 => i++, j++ => i=2, j=0 => p[i]==p[j],p[2]==p[0] => Next[i]=Next[j], Next[2]=Next[0]=-1(3)i=2, j=0 => j>-1&&p[2]==p[0] => i++, j++ => i=3, j=1 => p[i]!=p[j], p[3]!=p[1] =>Next[i]=j, Next[3]=1(4)i=3, j=1 => j>-1&&p[3]!=p[1] => j=Next[1]=0 => j>-1&&p[3]!=p[0] => j=Next[0]=-1=> i++, j++ => i=4, j=0 => p[i]==p[j], p[4]==p[0] => Next[i]=Next[j], Next[4]=Next[0]=-1(5)i=4, j=0 => j>-1&&p[4]==p[0] => i++, j++ => i=5, j=1 => p[i]==p[j], p[5]==p[1] =>Next[i]=Next[j], Next[5]=Next[1]=0(第一趟)i=0, j=0 => i>-1&&p[i]!=t[j] => i>-1&&p[0]!=t[0] => i>-1&&p[0]==t[0] => i++, j++ => i=1, j=1 => i>-1&&p[1]==t[1] => i++, j++ => i=2, j=2 => i>-1&&p[2]==t[2] => i++, j++ => i=3, j=3 => i>-1&&p[3]==t[3] => i++, j++ => i=4, j=4 => i>-1&&p[4]==t[4] => i++, j++ => i=5, j=5 => i>-1&&p[5]!=t[5] => i=Next[i], i=Next[5]=1(第二趟)=> i>-1&&p[1]!=t[5] => i=Next[i], i=Next[1]=0(第三趟)=> i>-1&&p[0]==t[5] => i++, j++ => i=1, j=6 => i>-1&&p[1]==t[6] => i++, j++ => i=2, j=7 => i>-1&&p[2]==t[7] => i++, j++ => i=3, j=8 => i>-1&&p[3]==t[8] => i++, j++ => i=4, j=9 => i>-1&&p[4]!=t[9] => i=Next[i], i=Next[4]=0(第四趟)=> i>-1&&p[0]!=t[9] => i=Next[i], i=Next[0]=-1 => i++, j++ => i=0, j=10 => i>-1&&p[0]==t[10] => i++, j++ => i=1, j=11 =>…………=> 全匹配成功(第一趟)i=0, j=0 => i>-1&&p[i]!=t[j] => i>-1&&p[0]!=t[0] => i>-1&&p[0]==t[0] => i++, j++ => i=1, j=1 => i>-1&&p[1]==t[1] => i++, j++ => i=2, j=2 => i>-1&&p[2]==t[2] => i++, j++ => i=3, j=3 => i>-1&&p[3]==t[3] => i++, j++ => i=4, j=4 => i>-1&&p[4]==t[4] => i++, j++ => i=5, j=5 => i>-1&&p[5]!=t[5] => i=Next[i], i=Next[5]=0(第二趟)=> i>-1&&p[0]==t[5] i++, j++ => i=1, j=6 => i>-1&&p[1]==t[6] => i++, j++ => i=2, j=7 => i>-1&&p[2]==t[7] i++, j++ => i=3, j=8 => i>-1&&p[3]==t[8] => i++, j++ => i=4, j=9 => i>-1&&p[4]!=t[9] => i=Next[i], i=Next[4]=-1 => i++, j++ => i=0, j=10(第三趟)=> i>-1&&p[0]==t[10] => i++, j++ => i=1, j=11 =>…………=> 全匹配成功。

数据结构 KMP算法

数据结构 KMP算法

问题的进一步分析:
S=“abcabeacadaadadasfsf” T=“abcabc” 上述第一轮比较在i j都为6时失败,传统的方案 是j=1,i=2进行下一轮,及如下: S=“abcabeacadaadadasfsf”
T=“abcabc” 而KPM告诉我们,应该这样: S=“abcabeacadaadadasfsf”
T=“abcde” 上式中,当i,j都为5时,比较失败,其时iห้องสมุดไป่ตู้回 溯,j从1开始,进行如下比较:
S=“abcdabcabababcde”
T=“abcde”
上例是特例,模式任一子串不是其它串的子串,即 字符互不相等。事实上:
1、我们可以相对容易的找出模式自身的特征;
2、我们依据刚比较的这一轮,结合模式内在特征 来找出模式回溯的位置
Times=5+1+3+1+1+5=16
KMP算法的思想是发现出模式内在的关联, 减少回溯:
极端的例子
目标 S=“abcdabcabababcde” 模式 T=“abcde” 可以想见,由于模式T所有字符都不相等,所
以如果某次比较失败后,目标指针根本不 需要回溯!
???
目标 S=“abcdabcabababcde” 模式 T=“abcde” 设目标的指针为i,模式的当前指针为j S=“abcdabcabababcde”
next(j) 0
1
1
1
2
2
3
2
3
KMP算法的思想就是:假设指针i ,j分别为主 串和子串不匹配所在的位置, 则i不变,j退 到next(j)所在的位置再进行比较,如相等, i,j各自增1,否则,当前的j再一次退到 next(j),直至j=1时,此时,i增1,子串则从头 开始
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

next的求解: a b a a a b a c b c 不必每次记录前缀后缀,前面匹配成功的字符,后面可以直接拿来 失配了,j要回溯,也就是模 用。
next的意义: 为什么求一个相同最长前缀 如果当前两个字符失配,那么模式串P应该移动到哪,换言之,应该用 P 后缀长度就可以解决这个问 中的哪个字符来继续匹配s[i]。保证文本串S的指针i不回溯。 题: 假设在模式串红色位置失配:
算法一的错误之处在于:如果出现没出现过的字符,会陷入死循环。
abaabca
next 0 0 0 1 1 ?
//i为next[]的下标,t为next[]的值 //-1和0都表示没有相同的前缀后缀 //t=-1同样可以达到next[1]=0的效果,想想为什么 //从1到(lenp-1)枚举i
a b a a b c a //①
abababcdabcdbbacabacaab abaca
abababcdabcdbbacabacaab abaca
abababcdabcdbbacabacaab abaca

abababcdabcdbbacabacaab abaca
abababcdabcdbbacabacaab abaca
这就来到KMP的大核心——next数组。 next数组表示的意思是当前字符之前的子串中最长相同前缀后缀的长度。 说人话:当前字符之前模式串P子串最长相同前缀后缀的长度。 手写个小Demo演示一下:
abaabca
next 0 0 0 1 1 2 0
注:一个字符串的相同前缀后缀是不包括这个字符串本身的,比如字符 串”ab”,它就没有相同前缀后缀,字符串”a”同理。
式串相对于文本串要右移。 右移多少位呢?我们发现, 既然当前位置前面的所有字 符都匹配成功,那么它最长 相同前缀后缀上的字符也都 相同。这些相同前缀后缀上 的字符不需要再匹配,用这 之中前缀的后面一个字符匹 配当前字符即可,即失配时, 模式串向右移动的位数为: 已匹配字符数 - 失配字符的 上一位字符所对应的最大长 度值。
//赋值next[] //②
①如果这是一个新字符(t==-1)那么就赋值next[i]为0(-1+1=0)。 ②t=next[t]的含义其实是t=next[t]-1+1。
next
-1
0
0
1
1
2
0
求完了next数组,下面就可以开始KMP了。 模拟之前提到的过程就可以,可以总结为下面两条规则: 规则一:如果匹配成功,i++,j++;
规则二:如果失配,i不动,j回溯到next[ j]。
代码十分容易理解,可能需要解释的就是输出模式串所在位置的条件, 详见下页。
//规则一 //规则二 //如果模式串最后一个字符也匹配成功就输出这个 //合法位置
如果整个模式串匹配成 功,j要回溯到next[j]。
至此,KMP算法介绍结束。 时间复杂度O(lens+lenp)。
谢谢~
abababcdabcdbbacabacaab abaca
事实上,我们在之前匹配的过程中已经知道了s[2]=b≠p[1]=a,i,j都回 溯必然失配。 那怎样降低时间复杂度呢? 引入KMP算法,使用这个算法可以将上面O(nm)的复杂度降低为 O(n+m)。 KMP算法的核心思想是:文本串s的指针i不回溯。 那是不是只需要在暴力的基础上保持失配时i不变就行了呢? 你会发现:还是浪费了很多时间。 有没有一种方法可以在失配时让j直接跳到一个应该跳到的位置上去呢?
相关文档
最新文档