找工作练手--KMP算法理解
来源:互联网 发布:手机淘宝官网找回密码 编辑:程序博客网 时间:2024/05/17 07:28
KMP算法讲解的实在太多了,各位作者为了它的严谨性,不惜花大量篇幅证明算法的正确性,也就用了很多公式去推导。曾经看了严蔚敏和唐宁九两位老师的,写的不错,花了不少时间。找工作在即,又花了点时间温习此算法,感觉比之前有了更多的感悟。
此算法的精髓在于运用匹配字符串P的右移省却了源字符串S的回溯过程,为什么右移以及右移多少位,这是该算法最关键的地方。为什么要右移,这个应该是显而易见的,匹配的过程就是P不断右移的过程;右移多少位,这应该是所有初学KMP算法的同学最困扰的地方了。
我的感悟就是:假设P=P1 P2 P3 .... Pi.....Pn在Pi处与S不匹配,此时P1 P2 P3 ... Pi-1都是已经匹配的,要算P要右移多少位,就是要算出P1 P2 P3 .... Pi-1中最大的K,把P1 P2 P3 ... Pi-1分成了两个字符串:P1 P2 .... Pk-1 和 Pi-k+1 Pi-k+2 ... Pi-1,使得这两个字符串正好匹配。
举例说明:
S = “acabaabaabcacx” P = "abaabcac"
第一趟:
S a c a b a a b a a b c a c x
P a b
此时在i = 2时 pi = b != c。此时按照上面我的所述,P1...Pi = a。而此时a仅仅是一个字符的字符串,无法拆分成两个,所以对于此时的右移比较特殊,直接右移一位即可。
第二趟:
S a c a b a a b a a b c a c x
P a
此时在i = 1处就不匹配了,i之前没有匹配字符串,所以特殊情况,直接右移一位。
第三趟:
S a c a b a a b a a b c a c x
P a b a a b c
此时在i = 6时不匹配,i之前有“abaab”是已经匹配的。这时的右移按照我上面所说要找到一个最大的K值把“abaab”划分成匹配的两个字符串。很容易看到此时K = 3,划分成的两个字符串分别是: P1 P2 = “ab” 和 P4P5 = “ab” 。
第四趟:
S a c a b a a b a a b c a c x
P a b a a b c
第四趟即为第三趟右移三位后的匹配过程,很清楚地看到此时匹配成功了。
右移多少位就是求next[i]的值,相信大家已经很清楚的知道为什么右移以及右移多少位是如何来的,也就是最大值K是怎么产生的。
详细的证明部分还请大家去看相关书籍吧,理解了上面说的这些,再去看严,唐二人的书,应该就很快了。
下面附上代码:
#include "string.h"// 串类// KMP匹配算法void getNext(const String &P, int next[])// 操作结果: 求模式串P的next数组的元素值{next[0] = -1;// 由next[0] = -1开始进行递推int j = 0, k = -1;// next[j] = k成立的初始情况while (j < P.Length() - 1){// 数组next的下标范围为0 ~ P.Length() - 1, 通过递推方式求得next[j+1]的值if (k == -1){// k == -1只在j == 0时发生next[j+1]=0;// next[j+1]=next[1] = 0j=1; k = 0;// 由于已求得next[1] = 0,所以j = 1, k = 0}else if (P[k] == P[j]){// 此时next[j+1] = next[j]+1next[j+1]=k+1;// 由于P[k] == P[j],所以next[j+1] = next[j]+1 = k + 1j++; k++;// 由于已求得next[j+1]=k+1,所以j更新为++j,k更新为++k}else{// P[k]与P[j]不匹配k = next[k];// 寻求新的匹配字符}}}int KMPIndexHelp(const String &T, const String &P, int pos, int next[])// 操作结果: 通过next数组查找模式串P第一次在目标串T中从第pos个字符开始出现的位置{int i = pos, j = 0;// i为目标串T中的当前字符位置,j为模式串P的当前字符位置while (i < T.Length() && j < P.Length()){if (j == -1){// 此时表明P中任何字符都不再与T[i]进行比较,下次P[0]与T[i+1]开始进行比较i++; j = 0;}else if (P[j] == T[i]){// P[j]与T[i]匹配i++; j++;// 模式串P与目标串T的当前位置向后移}else{// P[j]与T[i]不匹配j = next[j];// 寻找新的模式串P的匹配字符位置}}if (j < P.Length()) return -1;// 匹配失败else return i - j;// 匹配成功}int KMPIndex(const String &T, const String &P, int pos = 0)// 操作结果: 查找模式串P第一次在目标串T中从第pos个字符开始出现的位置{int *next = new int[P.Length()];// 为数组next分配空间getNext(P, next);// 求模式串P的next数组的元素值int result = KMPIndexHelp(T, P, pos, next);// 返回模式串P第一次在目标串T中从第pos个字符开始出现的位置delete []next;// 释next所占用的存储空间return result;}
- 找工作练手--KMP算法理解
- 找工作面试之二KMP算法
- KMP算法理解
- 深入理解KMP算法
- KMP算法的理解
- 理解KMP算法
- KMP算法初步理解
- 从头到尾理解KMP算法
- 从头到尾理解KMP算法
- KMP算法的理解
- KMP算法理解
- KMP算法---理解
- 从头到尾理解KMP算法
- 对KMP算法理解
- KMP算法理解
- 【算法】KMP的理解
- KMP算法的理解
- 理解KMP算法
- Andorid VS J2ME
- stdout, stderr的区别
- 多线程(J2SE学习随笔三)
- 汉字编码与编程相关问题总结:ASCII、机内码、区位码、国标码、Unicode码是如何转换的
- C语言中史上最愚蠢的Bug
- 找工作练手--KMP算法理解
- 13个对Android开发者有帮助的工具和资源
- Java中abstract和interface区别
- Java版线程池实现与原理
- 其他
- 安装VIM和GVIM的中文帮助手册
- [转]Smarty3.0 新特征
- 用简单的方法来访问GObject对象的私有属性
- X Note(1)