- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章快速模式匹配算法(KMP)的深入理解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
恐怕现在用过电脑的人,一定都知道大部分带文本编辑功能的软件都有一个快捷键ctrl+f 吧(比如word)。这个功能主要来完成“查找”,“替换”和“全部替换”功能的,其实这就是典型的模式匹配的应用,即在文本文件中查找串。 1.模式匹配 模式匹配的模型大概是这样的:给定两个字符串变量S和P,其中S成为目标串,其中包含n个字符,P称为模式串,包含m个字符,其中m<=n。从S的给定位置(通常是S的第一个位置)开始搜索模式P。如果找到,则返回模式P在目标串中的位置(即:P的第一个字符在S中的下标)。如果在目标串S中没有找到模式串P,则返回-1.这就是模式匹配的定义啦,下面来看看怎么实现模式匹配算法吧。 2.朴素的模式匹配 朴素的模式匹配算法非常简单,容易理解,大概思路是这样的:从S的第一个字符S0开始,将P中的字符依次和S中字符比较,若S0=P0 && …… && Sm-1 = Pm-1,则证明匹配成功,剩下的匹配无需进行了,返回下标0。若在某一步Si != Pi 则P中剩下的字符也不用比较了,不可能匹配成功了,然后从S中第二个字符开始与P中第一个字符进行比较,同理,也是知道Sm = Pm-1或者找到某个i使得Si != S-1为止。依次类推若知道以S中第n-m个开始字符为止,还没有匹配成功则证明S中不存模式P。(想想为什么这里强调是n-m)这个代码实现应该是非常简单的,具体开始参考strstr函数的内部实现。可以看看百度百科,给个链接http://baike.baidu.com/view/745156.htm,这里不写出来了,还得赶紧进入正题KMP呢。 3.快速模式匹配算法(KMP) 朴素的模式匹配效率不高的主要原因是进行了重复的字符比较。下一次比较和上一次比较没有任何的联系,是朴素模式匹配的缺点,其实上一次比较的比较结果是可以利用的,这就产生了快速模式匹配。在朴素的模式匹配中,目标串S的下标移动是一步一步的,这其实并不好,移动步数没有必要为1。 现在不妨假设,当前匹配情况是这样的:S0 …… St St+1 …… St+j 与 P0 P1…… Pj ,现在正在尝试匹配的字符是St+j+1和Pj+1,并且St+j+1 != Pj+1,言外之意就是说St St+1……St+j和P0 P1……Pj是完全匹配的。那么这个时候,S中下一次匹配开始位置应该是什么呢??按照朴素的模式匹配,下次比较应该从St+1开始,并且令St+1和P0比较,但是在快速模式匹配中并不是这样,快速模式匹配选择St+j+1和Pk+1比较,K是什么呢?K是这样的一个值,使得P0 P1……Pk 和 Pj-k Pj-k+1……Pj完全匹配,不妨设k=next[j],因此P0 P1……Pk和St+j-k St+j-k+1 ……St+j完全匹配。那么下一次要进行匹配的两个字符应为St+j+1和Pk+1。S和P都没有回溯到下标0在进行比较,这就是KMP之所以快的原因啦。 现在关键问题来了,这个K怎么能得到呢?如果得到这个K值复杂度高,那这个思路就不好了,其实这个K呢,只和模式串P有关系,并且要求m个k,k = next[j],因此只要算一次存储到next数组中就可以了,并且时间复杂度和m有关系(线性关系)。看看具体怎么求next数组的值,即求k。 用归纳法求next[]:设next(0) = -1,若已知next(j) = k,欲求得next[j+1]。 (1)如果Pk+1 = Pj+1,显然next[j+1] = k+1.如果Pk+1 != Pj+1,则next[j+1] < next[j],于是寻找h < k 使得P0 P1……Ph = Pj-h Pj-h+1……Pj = Pk-h Pk-h+1……Pk。也就是说h = next(k);看出来了吧,这是个迭代的过程。(也就是以前的结果对求以后的值有用) (2)如果不存这样的h,说明P0 P1……Pj+1中没有前后相等的子串,因此next[j+1] =-1. (3)如果存在这样的h,继续检验Ph和Pj是否相等。知道找到这中相等的情况,或者确定为-1求next[j+1]的过程结束。 看看实现的代码:
复制代码 代码如下
View Code int next[20] ={0}; //注意返回结果是一个数组next,保存m个k值得地方,即若next[j]=k //则str[0]str[1]…str[k] = str[j-k]str[j-k+1]…str[j] //这样当des[t+j+1]和pat[j+1]匹配失败时,下一个匹配位置为des[t+j+1]和next[j]+1 void Next(char str[],int len) { next[0] = -1; for(int j = 1 ; j < len ; j++) { int i = next[j-1]; while(str[j] != str[i+1] && i >= 0)//迭代的过程 { i = next[i]; } if(str[j] == str[i+1]) { next[j] = i+1; } else { next[j] = -1; } } } 。
现在有了next数组保存的k值,就可以实现KMP算法了:
复制代码 代码如下
View Code //des是目标串,pat是模式串,len1和len2是串的长度 int kmp(char des[],int len1,char pat[],int len2) { Next(str2,len2); int p=0,s=0; while(p < len2 && s < len1) { if(pat[p] == des[s]) { p++;s++; } else { if(p==0) { s++;//若第一个字符就匹配失败,则从des的下一个字符开始 } else { p = next[p-1]+1;//用失败函数确定pat应回溯到的字符 } } } if(p < len2)//整个过程匹配失败 { return -1; } return s-len2; } 。
时间复杂度: 对于Next函数近似接近O(m),KMP算法的时间复杂度为O(n),所以整个算法的时间复杂度为O(n+m) 空间复杂度: 多引入了O(m)的空间复杂度。 4.应用KMP的一道面试题 给定两个字符串是s1和s2,要判定s2是否能够被s1做循环移位得到的字符串包含。例如s1=AABCD,s2 =CDAA,返回true,因为s1循环移位可以变成CDAAB。给定s1=ACBD和s2=ACBD则返回false。 分析:不难发现对s2移位得到的字符串都将是字符串s1s1的子串,如果s2可以有s1循环移位得到,那么s2一定是s1s1的子串,这时KMP算法是不是就很管用了呢.
最后此篇关于快速模式匹配算法(KMP)的深入理解的文章就讲到这里了,如果你想了解更多关于快速模式匹配算法(KMP)的深入理解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
KMP 算法实例详解 KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其对于任何模式和目标序列,都可以在线性时间内完成匹配查找,而不会发生退化,是一个非常优秀的模式匹配
我正在尝试使用搜索算法KMP来计算模式出现次数和所需比较(在下面的代码中称为匹配)。 我尝试执行以下操作: public class KMP { private String pat;
我想搜索一个字符串(假设a)在字符串b中出现了多少次。我想过实现 Knuth-Morris-Pratt 算法,但我更喜欢内置的 java 函数。有这样的功能吗?我希望该函数的复杂性尽可能最低,因为我多
有人要求我了解 KMP DFA,我在书中找到的是该实现,但我们的讲师一直称其为“前缀函数”。我真的不明白这个功能是哪一部分,有人可以给我解释一下吗?很抱歉,如果有人在某个地方问过这个问题,但我找不到。
我正在尝试使用 CLRS 实现 KMP 字符串匹配算法,但是文本输入为“bbaa”,模式输入为“aab”,它陷入了 while 的无限循环在 getKMPPrefix 函数中循环。我的代码如下: pr
KMP 算法在最佳情况下的最少比较次数是多少? 最佳答案 最好的情况是您要查找的字符串刚好位于文本字符串的开头。在这种情况下,如果您要在 n 字母字符串中查找 k 字母字符串,则最好的比较次数是 k。
我已经实现了用于在字符串 B 中搜索字符串 A 的 Knuth-Morris-Pratt 算法。如果找到字符串,则返回字符串的第一个位置,否则返回 -1。但是现在我想统计字符串 A 在字符串 B 中的
最近学习了KMP字符串匹配算法,差不多搞定了。但我不明白的是如何在 O( length_of_pattern ) 中构建故障函数。我不需要代码,如果可能,我需要一个清晰的解释。提前致谢! 最佳答案 来
想知道是否有人可以提供一些关于选择 KMP 和后缀树之间的利弊的建议,如果我们想看看一个字符串是否是另一个字符串的子字符串?谢谢。 提前致谢,林 最佳答案 运行时和内存复杂度大致相同。您在 O(N)
如我所见,在 KMP 中构建故障/前缀表的主要函数(在所有在线资源中,甚至在这个 answer _ 中,如下所示: int j = 0; for (int i = 1; i 0 && pa
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 9
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
扩展kmp既是求模式串和主串的每一个后缀的最长公共前缀 即令s[i]表示主串中以第i个位置为起始的后缀,则B[i]表示s[i]和模式串的最长公共前缀 显然KMP是求s[i]=模式串长度的情况,所
先声明,本人菜鸟一个,写博客是为了记录学习的过程,以及自己的理解和心得,可能有的地方写的不好,希望大神指出。。。 抛出问题 给定一个文本串test_str(被匹配的字符串)和模式串pat_str
恐怕现在用过电脑的人,一定都知道大部分带文本编辑功能的软件都有一个快捷键ctrl+f 吧(比如word)。这个功能主要来完成“查找”,“替换”和“全部替换”功能的,其实这就是典型的模式匹配的应用,即
我想统计一篇文章的词频。 我的想法是先创建一个struct数组 struct{ char[WORD_SIZE] }data[MAX_WORD_NUMBER]; 然后读取每个字符然后确
您好,我正在尝试编写 KMP search 的 C# 版本来自 C 书中的算法。无法找到我的算法中的缺陷。有人愿意帮忙吗? static int KMP(string p, string str) {
我想找到字符串 S 中与正则表达式 R 匹配的所有子字符串。正则表达式只能包含“.”和符号(其中“.”表示任何符号)。我正在尝试使用 KMP 来解决这个问题: 1) 构建字符串 T = R + '#'
从函数返回一个向量会产生什么问题吗?还是只是一些基本的语法问题? 这只是CLRS中的示例代码. computePrefix 函数计算给定模式的正确前缀的值,并匹配主函数中的值。 获取 SIGSEGV
我正在寻找一种有效的算法,以在将 pattern 与文本进行比较时允许不匹配(最多 3 个)。原始 KMP 在我的数据上有效地完成了这项工作,但正在考虑扩展该算法以适应不匹配情况。 对于我的情况:GA
我是一名优秀的程序员,十分优秀!