转自: http://wenku.baidu.com/link?url=i9CzZhVzmq9hXKF53jgxFMssvIKLyK45ix7PmwYP7HS2jLNbjNA_kALg8hK1sa7nmpKW706PSaE98pJB_HeLKqPeMQAwJIwfSM3dry9ecEm
主要看了这里,感觉讲的十分的不错,总结一下。
首先声明要搜索的串为S,设长度为n,要匹配的串为M,设长度为m.
先考虑暴力的算法,暴力的算法是遍历S的每一个字符,然后从这个字符开始和M串进行匹配。时间复杂度为O(nm).
怎么在此基础上进行优化?假设现在从某个位置(设为s)开始和M串进行匹配,如果匹配不成功,暴力算法是从这个位置的下一个位置(s+1)进行匹配,直观上来说就是匹配的字符串向后“滑动”了一位。
能不能想办法让M向后移动的距离最大化?考虑最好的情况,如果和M匹配的S中的m个字符和M中的字符没有一个相等,那么能向右移动m位;考虑最坏的情况,比如上图,只能移动一位。
而KMP就是在这里做文章,让M串向后“滑动”的距离最大化。
考虑上面的图,M中灰色部分已经和S的灰色部分匹配上了,而灰色部分后一个字符不匹配,则现在M要向后滑动,假设一直向后滑动,直到如图位置又和S再一次匹配上了,那么从这里我们可以得到如下的结论:
A段字符串是M的一个前缀。
B段字符串是M的一个后缀。
A段字符串和B段字符串相等。
这样,如果暂时不考虑S,只看M的话,假设已经匹配的M的字串(即图中M中灰色部分)为subM,则subM有个【相等】的【前缀】和【后缀】。而且M在遇到不匹配的时候可以直接滑动到使subM的前缀和subM的后缀重合的地方。而M向后滑动的时候,第一次subM的前缀和后缀重合意味着此时这个相等的subM的前缀和后缀的长度是最大的。
我们的任务就是要寻找subM的最长的前缀和后缀相等的串。
知道了这一点,离KMP的真谛也就不远了。现在结合这上面的图模拟一下KMP算法的整个流程:
将S串和M串从第一个字符开始匹配;
如果匹配成功,则subM即灰色部分增加;
如果不成功,则M向后滑动使滑动后的subM的前缀和滑动前的subM的后缀重合,再进行匹配,如果还不成功,则再次滑动M,直到匹配成功或者M滑动到X处。如果到了X处,则从M串的起始位置进行匹配。
从上面的步骤可以知道,KMP的关键就是要知道当S串中的字符和M串中的字符不匹配时,S串要和M串中的哪个字符继续进行匹配。这个就是在利用状态机模型来解释KMP算法时的状态转移.
KMP是通过一个定义了一个next数组,这个next数组保存了如果S中的字符和M中的字符不匹配时S要和M中的哪个字符重新进行匹配的坐标值。如图2中所示是例子,S中的X位置和M不匹配了,那么S要和M中A段后面的字符进行比较,从图中来看是M向后滑动了。
换句话说,next[i]总是保存了当M[i]不匹配时要从M[next[i]]处进行匹配,这个M[next[i]]可能会匹配,如果还不匹配?那么可能会在M[next[next[i]]]处匹配了。这里同时隐含着一个信息,就是i之前的一段字符和next[i]之前的一段字符是相同的,也就是M[0…i-1]相等的前缀和后缀。
现在考虑next[0],next[1]…next[i]都已经知道了,那么图示如下:
设j=next[i],灰色部分表明这两段字符是相等的,如果i位置的字符和j位置的字符相等,那么next[i+1]=j+1;因为前一段灰色部分和j位置的字符组成的字符串和后一段灰色的与i连接所形成的字符串是相等的。这正是前面对next数组的定义。如果不相等,则要找到从i开始包括i往前的一段字符串与从0开始的一段字符串相等,这样形成相等的前缀和后缀。所幸我们知道next[next[i]]的值,因为next[i]前面的字串也有最长的公共前缀和后缀,而这个公共的前缀与现在i以及往前形成的字串可能相等,这样一直向前找,如果找不到,则说明i位置的字符从来没有在之前出现过。
这样求出来的next数组其实是从下标1开始的,因为下标0之前是个空串,下标1则对应着M串的第0个字符。我们设next[0]=-1,仅仅是个标志而已,没有什么特殊的含义。
那么根据前面所述,可以很容易的写出初始化next数组的代码
1: void kmpGetNext()
2: {
3: int i=0, j=-1;
4: b[i]=j;
5: while (i<m)
6: {
7: while (j>=0 && p[i]!=p[j]) j=b[j];
8: i++; j++;
9: b[i]=j;
10: }
11: }
知道了next数组的值,则和S串进行匹配则相对简单了,因为如果碰到不匹配的时候去查找next数组即可,直到找出和当前字符匹配的那个字符。如果找不到怎么办?找不到则会得到-1,也就是没有字符和他进行匹配,那么跳过这个字符,直接从下一个字符进行匹配即可。
代码如下:
1: void kmpSearch()
2: {
3: int i=0, j=0;
4: while (i<n)
5: {
6: while (j>=0 && t[i]!=p[j]) j=b[j];
7: i++; j++;
8: if (j==m)
9: {
10: report(i-j);
11: j=b[j];
12: }
13: }
14: }
看到上面的代码,两层循环,貌似这个代码并不是线性的,其实不然。外层循环了n次这个没有问题,关键是里面的while循环,这个循环的次数是多少并不好确定,然而考虑单单考虑j的值的变化,会发现第七行j增加1,而第6行j则减少,可能减少1,可能减少2,可能少的更多,但是j<0时循环就终止了,也就是说j有n次增加的机会,会有多少次减少的机会?或者问j最多减少多少次?j减少的次数最多的时候,就是每次减少1,这样最多的会减少n次,也就是说第六行的循环最多会执行n次。平摊到每个循环,则执行次数为O(1),所以kmpSearch的时间复杂度仍然是线性的O(n),同理,kmpGetNext的时间复杂度为O(m).详情请参考matrix67大牛的文章,下面有犀利的评论:
倒数第七段
“…每一次执行while循环都会使j减小(但不能减成负的),而另外的改变j值的地方只有第五行。每次执行了这一行,j都只能加1;因此,整个过程中j最多加了n个1。于是,j最多只有n次减小的机会(j值减小的次数当然不能超过n,因为j永远是非负整数)。这告诉我们,while循环总共最多执行了n次。… ”
这里不大明白,整个过程中j是在回退然后前进的,假设第一遍比较回退一次,第二遍比较回退两次,于是总共加起来j减小和变大的次数都要大于n,不是吗?
回复:我每年新交1个MM,我100年内会失恋200次吗?
相关推荐
16_单链表小结:腾讯面试题. mp4品17_ 线性表12. mp418_约瑟夫问题. mp4西19_ 线性表14. mp4 20_魔术师发牌问题. mp421线性表16. mp4逾22_ 线性表17. mp423_栈和队列. mp424_栈和队列2. mp4面25_ 进制转换. mp4面26_...
小结 42 参考文献 43 附录A 算法源码 45 1 BM算法 45 2 BMH算法 46 3 BMHS算法 46 4 . smith 算法 47 5.kmp算法 47 A 6 自动机算法 47 A 7 bom 算法 48 A 8 shift-or 算法 50 A 9 BNDM算法 51 A 10 哈希法 51
- 还有一些博客文章提供了更深入的讲解,包括算法小结和动画分析,帮助直观地理解KMP算法的基本思想。 总的来说,KMP算法是字符串处理中的一种经典算法,对于准备参加NOI和NOIP的选手来说,熟练掌握KMP算法及其应用...
除了最长回文串匹配,还提到了KMP算法,它是一种字符串匹配算法,用于在一个文本串(T)中查找一个模式串(P)的出现次数。KMP算法的关键在于计算模式串的next数组,该数组记录了模式串中每个字符之前可以跟哪些字符...
相比传统的单模式匹配算法如KMP算法、Boyer-Moore算法等,Wu-Manber算法能同时处理多个模式串,适用于大规模数据集的搜索任务。但原有的Wu-Manber算法在处理某些特殊情况时,尤其是当模式串之间存在后缀关系时,其...
9. **字符串处理**:书中探讨了字符串匹配算法,如朴素算法、KMP算法、Boyer-Moore算法等,这些都是文本处理中的重要工具。 10. **计算复杂性理论**:简要介绍了P、NP问题、时间复杂度和空间复杂度的概念,帮助读者...
字符串处理算法,如KMP、Rabin-Karp和Boyer-Moore,用于高效的文本匹配。递归和分治策略是解决复杂问题的有效方法,如快速幂运算、归并排序和分治法求解斐波那契数列。 《数据结构与算法分析——Java语言描述.pdf》...
- 操作:如子串提取、合并、长度计算和模式匹配,KMP算法用于高效模式匹配。 6. 数组: - 高维数组的存储:行优先和列优先,特殊矩阵的存储结构。 7. 树与二叉树: - 基本概念:结点、度、深度、层次、根、叶子...
5. **字符串**:字符串处理也是数据结构的一个重要部分,涉及字符串的查找、替换、比较等操作,以及模式匹配算法,如KMP算法。 6. **排序与查找算法**:包括冒泡排序、插入排序、选择排序、快速排序、归并排序、堆...
8.8 排序知识点小结 258 ▲真题仿造 259 真题仿造答案与解析 259 习题 真题精选 260 习题答案 真题精选答案 265 9 章 查找 275 大纲要求 275 考点与要点分析 275 核心考点 275 基础要点 275 知识点讲解 275 9.1 查找...
知识点:KMP 算法是一种字符串模式匹配算法,它可以在 O(n) 时间复杂度内完成模式匹配,不需要回溯。 5. 图的生成树是该图的极小连通子图。 知识点:图的生成树是指该图的极小连通子图,它是图的最小连通子图。 ...
这是因为 KMP 算法是一种字符串匹配算法,它使用next函数来记录模式串的信息。 三、简答题: 1. 在 n 个不同的英文单词中,采用什么排序方法时间复杂度最佳?由于 n>>50,m,采用基于比较的排序算法的时间复杂度将...
- **知识点**: KMP算法是一种高效的字符串匹配算法,它通过预先计算模式串的部分匹配表来避免不必要的回溯。 - **解析**: KMP算法确实是一个不需要回溯的字符串模式匹配算法,因此此判断题的说法是正确的。 5. **...
实训中可能涉及串的创建、删除、插入、查找、替换等操作,以及串的模式匹配算法,如KMP算法。 3. **队列**:队列是一种“先进先出”(FIFO)的数据结构,常用于任务调度、缓冲区管理等。队列的基本操作包括入队...
7. **字符串**:字符串处理中的模式匹配问题,如KMP算法和Boyer-Moore算法。 8. **算法分析**:涉及到时间复杂度和空间复杂度的分析,为优化算法提供理论依据。 书中的C语言代码实现部分,可以帮助读者更直观地...
这是关于字符串匹配算法的问题,通常涉及到KMP算法、Boyer-Moore算法或Rabin-Karp算法等,这些算法能够高效地查找目标串T在模式串P中是否存在,并找出匹配的位置。 以上就是从题目中提取出的相关知识点,涵盖了数据...
10. **KMP算法**:字符串'acaba'的next数组值表示了子串的最长公共前缀,其next数组为01212。答案是B。 11. **二路归并排序**:第一趟2-路归并排序后得到5个长度为2的有序表,第二趟归并后应保持有序。通过比较各...
算法小结 0、排序 快速排序 快速排序 第K个数 归并排序 归并排序 逆序对的数量 1、二分 整数二分 数的范围 小数二分 数的三次方根 2、前缀和 一维前缀和 前缀和数组 二维前缀和 子矩阵的和 3、差分 一维差分 差分数...
- KMP算法计算next函数,用于字符串匹配,避免回溯,具体计算涉及模式串的滑动窗口。 - Huffman编码是基于最小带权路径长度的最优前缀编码,通过构造Huffman树来实现。 - 关键路径分析是图论中的概念,用于找出...
7.4 小结 81 第三部分 配置问题 第8章 策略 83 8.1 导引 83 8.2 策略定义的要求 84 8.3 策略的表示与分布 85 8.4 策略管理系统 86 8.4.1 内核支持 86 8.4.2 IKE支持 87 8.5 配置 87 8.6 策略的设置 88 第9章 IPSec的...