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

合集下载

kmp

kmp


这个程序或许比想像中的要简单,因为对于i值的不断增加,代码用的是for循环。因 此,这个代码可以这样形象地理解:扫描字符串A,并更新可以匹配到B的什么位置。 思考,那个while循环能保证是常数级么? p数组怎么求出来?
对于while循环的分析

为什么这个程序是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)。
kmp
本ppt大部分来自网络 matrix67
思路来源




pascal里有个叫 pos的 string 函数。 cpp里string类里有个find成员函数 有两个串A和B(length(A)>=length(B)),我们要找B 在A中第一次出现的位置。 如果没有pos,怎么办? 最裸的。 通常我们的方法是枚举从A串的什么位置起开始与B 匹配,然后验证是否匹配。假如A串长度为n,B串长 度为m,那么这种方法的复杂度是O (mn)的。 有人会说只要有不匹配就可以break,那样不会到m*n。

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个过程中的 任意一个,直到模式串走到结尾为止。

小学信息课件:-第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算法KMP算法应该是每⼀本《数据结构》书都会讲的,算是知名度最⾼的算法之⼀了,但很可惜,我⼤⼆那年压根就没看懂过~~~之后也在很多地⽅也都经常看到讲解KMP算法的⽂章,看久了好像也知道是怎么⼀回事,但总感觉有些地⽅⾃⼰还是没有完全懂明⽩。

这两天花了点时间总结⼀下,有点⼩体会,我希望可以通过我⾃⼰的语⾔来把这个算法的⼀些细节梳理清楚,也算是考验⼀下⾃⼰有真正理解这个算法。

什么是KMP算法:KMP是三位⼤⽜:D.E.Knuth、J.H.Morris和V.R.Pratt同时发现的。

其中第⼀位就是《计算机程序设计艺术》的作者!!KMP算法要解决的问题就是在字符串(也叫主串)中的模式(pattern)定位问题。

说简单点就是我们平时常说的关键字搜索。

模式串就是关键字(接下来称它为P),如果它在⼀个主串(接下来称为T)中出现,就返回它的具体位置,否则返回-1(常⽤⼿段)。

⾸先,对于这个问题有⼀个很单纯的想法:从左到右⼀个个匹配,如果这个过程中有某个字符不匹配,就跳回去,将模式串向右移动⼀位。

这有什么难的?我们可以这样初始化:之后我们只需要⽐较i指针指向的字符和j指针指向的字符是否⼀致。

如果⼀致就都向后移动,如果不⼀致,如下图:A和E不相等,那就把i指针移回第1位(假设下标从0开始),j移动到模式串的第0位,然后⼜重新开始这个步骤:基于这个想法我们可以得到以下的程序:1/**23 * 暴⼒破解法45 * @param ts 主串67 * @param ps 模式串89 * @return如果找到,返回在主串中第⼀个字符出现的下标,否则为-11011*/1213public static int bf(String ts, String ps) {1415char[] t = ts.toCharArray();1617char[] p = ps.toCharArray();1819int i = 0; // 主串的位置2021int j = 0; // 模式串的位置2223while (i < t.length && j < p.length) {2425if (t[i] == p[j]) { // 当两个字符相同,就⽐较下⼀个2627 i++;2829 j++;3031 } else {3233 i = i - j + 1; // ⼀旦不匹配,i后退3435 j = 0; // j归03637 }3839 }4041if (j == p.length) {4243return i - j;4445 } else {4647return -1;4849 }5051 }上⾯的程序是没有问题的,但不够好!(想起我⾼中时候数字⽼师的⼀句话:我不能说你错,只能说你不对~~~)如果是⼈为来寻找的话,肯定不会再把i移动回第1位,因为主串匹配失败的位置前⾯除了第⼀个A之外再也没有A了,我们为什么能知道主串前⾯只有⼀个A?因为我们已经知道前⾯三个字符都是匹配的!(这很重要)。

KMP算法

KMP算法

这里有一点要注意,前缀必须要从头开始算,后缀要从最后一个数 开始算,中间截一段相同字符串是不行的。
Next数组
SKtrMinP g
再回到next[i]的定义,对于字符串ptr = "ababaaababaa"; next[1] = -1,代表着除了第一个元素,之前前缀后缀最长的重复子串,这 里是空 ,即"",没有,我们记为-1,代表空。(0代表1位相同,1代表两位 相同,依次累加)。 next[2] = -1,即“a”,没有前缀与后缀,故最长重复的子串是空,值为 -1; next[3] = -1,即“ab”,前缀是“a”,后缀是“b”,最长重复的子串 “”; next[4] = 1,即"aba",前缀是“ab”,后缀是“ba”,最长重复的子串 “a”;next数组里面就是最长重复子串字符串的个数
2.{
3.
j = next[j];
4.}
KMP算法匹配求解
加上上面的代码进行组合: 在对两个数组进行比对时,各自的i,j取值代码:
while( i<ptr.length && j< a.length) {
if( j==0 || ptr[i]==a[i] ) {
++i; ++j; next[i] = j; } else {
假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置 如果j = -1,或者当前字符匹配成功(即S[i] == P[j]),
都令i++,j++,继续匹配下一个字符; 如果j != -1,且当前字符匹配失败(即S[i] != P[j]),则
令 i 不变,j = next[j]。此举意味着失配时,模式串P相对于文本串S 向右移动了j - next [j] 位。

数据结构课件-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算法(推导方法及模板)

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

问题的进一步分析:
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[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无关。
我们可用递推的方法求next数组值。 假设已求得next[j]=k,根据定义可得 ‘p0p2……pk-1’= ‘pj-kpj-k+1……pj-1’ 那么next[j+1]=?
示例:
2020/12/10
4
算法分析
假设正文为‘s0s1……sn-1’,模式为 ‘p0p1……pm-1’,要实现改进算法,也就 是要解决下述问题:当匹配过程中产生 失配时(即si != pj),模式“向右滑动”可 行的距离有多远,换句话说,当正文中 第i个字符与模式中第j个字符“失配”时, 正文中第i个字符应与模式中哪个字符相 比较?
并令next[j]=k。
Next数组的完整定义如下:
-1 当j=0时;
next[j]=
Max{ k | 0<k<j 且‘p0p2……pk-1’= ‘pjkpj-k+1……pj-1’ } 当此集合不为空时
0 其他情况
2020/12/10
8
Next[0]=-1表示当模式p的第0个字符失去 匹配时应将p沿正文方向右移一个位置, 也即使p的第一个字符与正文s的下一个 字符进行比较。
第四章 字符串模式匹配算法
什么是模式匹配?
在一般的编辑软件中,经常要遇到在一 个给定的文本中查找一个特定的字符串 的问题,这就是字符串匹配,也称模式 匹配。
设P是一个模式字符串(简称模式),其长 度为m;s是一个正文字符串(简称正文), 其长度为n。n>>m
2020/12/10
1
简单算法(Brute-Force算法)
•而
kn = next[kn-1]
• 2020/12/10
k1 =k= next[j]
14
PPT教学课件
谢谢观看
Thank You For Watching
要使得k转为k2,实际上就是将p往右移,移动 后p’的j对应p的k2。
2020/12/10
12
k2,到底是多少首先取决于另一个前提条件:
‘p0p1……pk2-1’= ‘pj-k2pj-k2+1……pj-1’
如图:
0 j-k+1
j
p1
k- k2 +1
j p2
0
k
j p3
0
k2 k
实际上,
k2=next[k]
2020/12/10
3
模式匹配的KMP算法
基本思想:
当模式p与正文s进行比较的过程中发现 不匹配时,找到一种模式p沿正文s向后 移动的规则,以便使得正文s中失去匹配 的字符以前的字符不再参与比较,即只 从当前失去匹配的字符开始与模式p中的 字符继续依次进行比较,并且又不错过 模式被发现的机会。
2020/12/10
10
有两种可能情况
1、若pk=pj,则表明‘p0p1……pk’ = ‘满p足j-k上pj-式k+1,…那…么pj’,并且不可能存在k’>k
k next[j+1]= +1
式1
也就是:next[j+1]=next[j]+1
2、若pk!=pj,则表明‘p0p1……pk’ ! = ‘pj-kpj-k+1……pj’
2020/12/10
5
假设此时应与模式中第k个字符继续比较,其 中k应具有以下两个性质:
1、k<j,因为当失配时必然使模式p向后移, 从而导致k<j。移的幅度越小,k与j相差越小。
2、k应取所有可能值中的最大值,因为取最大 值就意味着移的幅度最小,也就避免错过成功 匹配的机会。
根据这个假设,必然使得下式成立:
2020/12/10
13
• 那么,满足了这个前提条件,是否就满 足pk2=pj了呢?
• 显然两者互不相干。也就是说,仅移动 一次不一定满足pk2=pj 。
• 如果移动一次后得到k2仍然不满足pk2=pj , 就要按照前提条件再移动一次。
• 依次类推,直到pkn=pj ,或kn=0为止。
• 此时有: next[j+1]= kn +1
‘p0p1……pk-1’=‘si-ksi-k+1……si-1’
(1)
而已经得到的“部分匹配”的结果是:
‘pj-kpj-k+1……pj-1’=‘si-ksi-k+1……si-1’
2020/12/10
(2) 6
(2)式的由来是:
当初正文中的第i个字符与模式中的第 j个字符失配时,说明两者之前的j个字符 肯定是一样的,而k<j,所以前k个字符也 是相同的。这就得出(2)式。
算法描述:
从正文s和模式p的第一个字符出发,将s 和p的字符依次逐个进行比较,如果p中 的所有字符均与s中的对应字符匹配,则 说明匹配成功;如果在比较过程中发现 了一个字符不匹配,则将模式p沿正文s 向后移动一个字符的位置,然后再从p的 第一个字符开始与中的对应字符逐个进 行比较。以此类推,直到匹配成功或到 达的末段为止。
相关文档
最新文档