【算法】KMP算法超详好懂理解(附全程序模拟过程)
来源:互联网 发布:java的compareto 编辑:程序博客网 时间:2024/06/03 19:36
KMP算法详解
当前稿件版本1.0
- KMP算法详解
- 前言
- 正文
- KMP是什么
- KMP大体是怎么运作的之规定篇
- KMP大体是怎么运作的之模拟主程序solve篇
- KMP大体是怎么运作的之模拟部分匹配值PMT_find篇
- 代码
前言
今天为了NOIP提高组的模拟准备,早上起来——默写KMP吧!好,提交:TLE;改改改:TLE;我不信!:TLE;58%%RS@^$:WA
终于在一天的努力后,把KMP给A了。
痛心疾首,决心写一个KMP的详解,不要让其他人掉入这个坑里了
正文
KMP是什么
来源在哪里不用管!只用知道它是一个高效的字符串匹配算法就行了。
AC自动机就是在Trie树上做一个KMP罢了。
故学好KMP还是蛮重要地。
KMP大体是怎么运作的之规定篇
嘿嘿嘿,开始模拟吧!
等等!直接开始模拟会有一些奇怪的问题,不利于理解,毕竟这个博客打的是超详好懂理解的标题,自然要先做出一些规定:
1. father son均为从0开始的string类型,father son分别为父串和子串
2. PMT为部分匹配值,为了和son保持一致,也是从0开始。
3. 变量i为father正在对比的字符下标【模拟中以红色标出】
4. 变量compared为son正在对比的字符下标【模拟中以黄色标出】
5. compared也代表了有几个字符匹配成功
好了开始模拟吧
KMP大体是怎么运作的之模拟主程序solve篇
以6do8_8__8q找出8__8q为例
这个是最原始的表格:
add为下标的号码,father、son同规定所示
有一个数组,名为PMT(Partial Match Table),部分匹配值的英文全称的简写。通过PMT_find
函数求出其值(这里省略,下文会提及)
开始对比,初始化compared=0;for(i=0;i<father.size();++i)
此时两个字符不等,compared为0,所以i++,compared保持不动
同理直至i=3时
因为son[compared]==father[i],所以compared++,i++
但是当i=5,compared=2时,又一次不相等
此时按照暴力来说,自然是compared=0,i++但是KMP不一样
它会搞一个大新闻,将compared=PMT[compared-1]等等,是0?额…是这个样例的问题,不用理!(注释:这一段的操作用文字叙述就是:用已匹配的字符数-其对应的部分匹配值)
例如在father="BBBBA",son="BBA"时,i=2,compared=2时会这样子:
compare=PMT[compared-1],即为1,因为循环的因素i依然++,于是就成为了这样子
看出PMT可以减去一些枚举。
接下来就是各种compared++与i++了,最后compared==son.size(),结束循环
注意:此时son[compared]越界了,所以注意程序处理顺序
KMP大体是怎么运作的之模拟部分匹配值PMT_find篇
部分匹配值的官方解释是:”前缀”和”后缀”的最长的共有元素的长度。
“部分匹配”的实质是,有些字符串头部和尾部会有重复。比如,”ABCDAB”之中有两个”AB”,那么它的”部分匹配值”就是2(”AB”的长度)。搜索词(即i、compared移动)移动的时候,第一个”AB”向后移动4位(字符串长度-部分匹配值),就可以来到第二个”AB”的位置。
那么怎么求呢,就是根据上一位以及上一位的字串来进行判断求max(因为字串的部分匹配值总是比母串大,所以直接搜就可以了)
- 貌似还是有点难懂啊,就拿ABABAC说吧,假设正在第3个A上做判断,前面有了个ABA,如果这里(即以第三个A为最后一个字符)有一个ABA——岂不美哉?
- 假设正在C上做判断,前面有一个ABAB,如果这里有一个ABAC不好么?然而没有…好的,那么此时是不是搜第二个B的BA?不是的,ABABA的最长出现字串是AB(BA也可以,但是C后面是A,A的视角中是AB),因此AB==AC?不,这么一直搜下去,没有……那就是0呗!
不懂的朋友们,拿起纸和笔,来手动按照下面的源码来一发模拟吧!自己动手才好理解
代码
/*build 2017.7.22*/#include<iostream>#include<cstring>#include<cstdio>using namespace std;const int maxlenth=100001;bool flag=0;int want;int PMT[maxlenth];string father;string son;void PMT_find(){ int comparing; PMT[0]=0; for(int i=1;i<want;++i) { comparing=PMT[i-1]; while(son[comparing]!=son[i]) { if(comparing==PMT[comparing]) break; comparing=PMT[comparing]; } if(son[comparing]==son[i]) ++comparing; PMT[i]=comparing; }}void solve(){ int compared=0; for(int i=0;i<father.size();++i) { /*if(father[i]!=son[compared]) { i=i+(compared-PMT[compared]); compared=PMT[compared]; } if(father[i]==son[compared]) ++compared;*/ //优化 while(compared and father[i]!=son[compared]) { compared=PMT[compared-1]; } if(father[i]==son[compared]) ++compared; if(compared==want) { flag=1; cout<<i+1-want+1<<endl; compared=PMT[compared-1]; } }}int main(){ ios::sync_with_stdio(false); cin>>father>>son; want=son.size(); PMT_find(); /* for(int i=0;i<son.size();++i) { cout<<PMT[i]<<" "; } cout<<endl; */ solve(); if(flag==0) { cout<<"no"<<endl; } return 0;}
- 【算法】KMP算法超详好懂理解(附全程序模拟过程)
- 比较好懂的KMP算法解释(附next数组求解方法)
- 超详细理解:kmp算法next数组求解过程和回溯的含义
- 浅析KMP算法(附C++源码)
- 一篇超容易让人理解的KMP算法文章
- KMP算法(1):如何理解KMP
- KMP 算法(1):如何理解 KMP
- KMP 算法(1):如何理解 KMP
- KMP 算法(1):如何理解 KMP
- KMP 算法(1):如何理解 KMP
- 理解KMP算法(引用)
- kmp 算法(有待理解)
- KMP 算法(个人理解)
- KMP算法理解(转)
- KMP算法理解(转)
- 超易懂KMP算法详解
- KMP算法超详细入门
- KMP算法代码实现和优化(不太能理解具体的过程和该算法思想)
- 线段树、前缀数组:HDU1591-Color the ball(区间更新、简单题)
- 第二章 K-近邻算法
- Linux vim命令、geit
- Linux虚拟机复制网卡启用不了
- C/C++中sizeof()的用法——32位和64位下的sizeof()
- 【算法】KMP算法超详好懂理解(附全程序模拟过程)
- js初级原理
- 11-S3C2440驱动学习(八)嵌入式linux-块设备驱动(2)之Nand Flash驱动
- Codeforces Round #124 (Div. 1) E. Opening Portals
- hello word!
- Multiply Strings问题及解法
- hdu 1285 确定比赛名次
- HDU
- PAT 1039到底买不买