菜鸟都能理解的看毛片(KMP)算法
来源:互联网 发布:excel筛选后数据求和 编辑:程序博客网 时间:2024/04/19 08:28
首先,允许我标题党了,看毛片算法和毛片没啥关系,如果你不小心进来了,那么我只能说呵呵了,呵呵^ ^
KMP算法其实是一个O(n)的字符串匹配算法
A = "ababacbacab"
B = "baca"
假设位置从1开始
这样可以说B是A的一个子串,首先我们想到的办法是枚举A的位置,比如
1.首先枚举位置A[1],即字符'a',然后从A[1]开始比较"abab"是否等于"baca",显然不等
2.接着枚举位置A[2],即字符'b',然后从A[2]开始比较"baba"是否等于"baca",显然,又不匹配
......
经过不断得尝试,我们终于枚举到一个位置A[7]开始的子串"baca"与B相等,my god,真不容易
我们来计算一下时间复杂度,我们枚举A的位置,最多有O(A.length())个位置,并且每个位置最多要匹配O(B.length()),所以,算法复杂度当然是O(A.length()*B.length())的啦
下面我们来见识一下神奇的看毛片算法
看毛片算法的思想是用两个指针i和j来指示A和B中的一个位置
1) 用i来表示当前匹配到A中的哪个位置啦
2) 用j来表示当前匹配到B中的哪个位置啦
3) 并且要满足B[1...j]要和A[i+j-1...i]相等
哦?很难理解啊,下面的图(图1)应该使你能够一拍脑袋,“哦,我太聪明了,这么简单!”
图1
灰色部分相等的啦^ ^
算法开始前,我们先考虑下面一个东东
指示数组p满足p[j]表示使得B[1...p[j]] = B[j-p[j]+1...j](图3)
图3(图片太大,新窗口打开吧亲)
灰色的两个部分相等
简单推理一下,你猜猜看三个红色的部分是不是也相等(请务必搞懂,非常重要)?答案是肯定的
算法开始咯:我们要考虑这个问题,i和j应该怎么增长
① 如果A[i+1] = B[j+1]
那么,我们只需要将两个灰色框子往后面拖动一格就行了哇(图2),并且,如果j变成B.length(),那么我们的匹配过程就结束咯,聪明的你一定理解吧?
图2
灰色部分相等的啦^ ^
② 如果A[i+1] != B[j+1]呢?
回顾一下i和j的定义先(看图1即可),我们可以将j改为p[j],显然更改后的p[j]任然满足图1哦,改完后,图1接下来扩展成介个样子哩(图4)
图4(对照图1和图3看哦)
调整了一下j的位置,我们又得到了一个新的j啦(j = p[j]),聪明的你如果看不懂图4只能说明。。。傻傻的我讲述得还不够清楚,欢迎留言开骂~
接下来呢,我们得看看B[p[j]+1] == A[i+1]成立否,这里,我们不知不觉又递归到“算法开始咯”,请你去递归着玩玩吧。。。
很开心地告诉你,看到这里,你已经几乎明白了KMP算法的整个流程,可以去上个厕所先,回来之后我们继续剩下的步骤,喝口茶,慢慢欣赏吧
欢迎回来,呃,继续....
罗里吧嗦一大堆,终于可以上代码咯,你会发现这个过程如此简单,亮瞎你的钛合金神眼,这就是编程之美,上!
for (j = 0, i = 0; i < n; ++i) { while (j > 0 && B[j+1] != A[i+1]) j = p[j];//看图4啦 if (B[j+1] == A[i+1]) ++j; if (j == m) { //如果B串都结束了,那么显然成功匹配咯 cout << "匹配成功: " << i - m + 1 << endl; j = p[j]; //使得可以继续匹配下去,这个你自己画个图就明白为啥要这么做咯 } }
复杂度分析:我们首先观察i,由于我们是依次扫描A数组中i的位置,所以你有木有发现i一直在增加,并且i只能增加A.length()次?而++i,++j是靠在一起的语句,所以呢j最多也只能增加A.length()次,并且j = p[j]语句说明j一直在减少,由于j只能增加A.length()次,所以j顶多也只能减少A.length()次,否则,j不是成了负数了嘛,而我们观察while(1)里面的内容发现,j每次不是增加就是减少,所以增加和减少(最外层的if elseif)两个语句加起来顶多执行2*A.length()次,所以呢,这个时间按复杂度当然是O(A.length())的啦
聪明的你一定还发现我们还有一个问题木有解决,就是,指示数组P!,我会告诉你P通过O(B.length())就能搞定的么?
假定我们已经知道p[1], ...p[j]是多少了,我们如何来构造p[j+1]呢,诶呀,我都口干舌燥了,喝口水慢慢来,上个图先(图5)
图5(最好保存下来看,图太大了,坑爹的csdn没有滚动条!!!)
相信你仔细观察上图之后我不用多做解释就能知道p[j+1]的构造过程了吧,你只需要搞清楚p[j]的定义,一切问题都是很轻松的KO掉的
p构造过程源码如下
p[1] = 0; for (j = 1; j <= m - 1; ++j) { k = j; while (k > 0 && B[j+1] != B[p[k]+1]) k = p[k]; p[j+1] = (k!=0 ? p[k]+1 : 0); }
最后,放出完整源码
#include <iostream>#include <string>using namespace std;int main() { string A = " ababababafcbaababafcc"; //string A = " ababafcc"; string B = " ababafcb"; int p[20]; int n = A.size() - 1; int m = B.size() - 1; int i, j, k; p[1] = 0; for (j = 1; j <= m - 1; ++j) { k = j; while (k > 0 && B[j+1] != B[p[k]+1]) k = p[k]; p[j+1] = (k!=0 ? p[k]+1 : 0); } //进行匹配 for (j = 0, i = 0; i < n; ++i) { while (j > 0 && B[j+1] != A[i+1]) j = p[j]; if (B[j+1] == A[i+1]) ++j; if (j == m) { cout << "匹配成功: " << i - m + 1 << endl; j = p[j]; } } return 0;}
感谢matrix67大神的文章http://www.matrix67.com/blog/archives/115
- 菜鸟都能理解的看毛片(KMP)算法
- 菜鸟都能理解的KMP算法
- KMP-看毛片算法
- kmp(看毛片)算法详解
- KMP-看毛片算法 c++
- 看毛片(KMP)算法简析
- 初次接触kmp看毛片算法
- kmp“看毛片”算法模板题
- 字符串匹配KMP(看毛片)算法
- 字符串匹配之看毛片算法-KMP
- KMP(看毛片)-
- 【字符串匹配】——KMP(看毛片算法)——深入讲解next数组的求解
- 菜鸟都能理解的线段树入门经典
- 菜鸟都能理解的线段树入门经典
- 菜鸟都能理解的线段树入门经典
- KMP (看毛片算法) 养成篇 (一)(启发篇)
- HDU--杭电--1711--Number Sequence--KMP--水题,看毛片算法基础死方法运用
- 萌新的看毛片(kmp)学习日记(下标从0开始)
- 出现“unrecognized selector sent to instance”问题原因之一及解决方法。
- VC++6/2005/2010里调试DLL
- mac键盘记录
- 棋谱管理系统工作日志
- Spring集成log4j日志管理
- 菜鸟都能理解的看毛片(KMP)算法
- WebService系列博客{十一}[CXF整合spring实际案例]
- 实现数据库同步的两种方法,SQL JOB和发布订阅
- c++和Python之rfind不同
- android开发 jar包引入编译正常运行时找不到
- VC2008界面编程
- strtol()详解
- 突破Outlook2013附件大小限制
- Android权限之sharedUserId和签名