KMP算法学习小结
来源:互联网 发布:网络与新媒体概论 编辑:程序博客网 时间:2024/06/05 04:40
晕,弄了一上午总算是搞懂了kmp的原理了,代码虽然短,但要理解好真心是蛋疼啊!
其实网上的那些什么“彻底弄懂kmp算法”什么的,感觉讲的好生涩,对于一个学渣来讲还真是难懂。
所以这里推荐一篇,自认为这一篇是最好懂的了。
链接:(http://kb.cnblogs.com/page/176818/)
其实,kmp的核心并不是这整一套算法,而是这套算法中的一个重要部分。毕竟还有更牛的叫“Boyer Moore”算法,这些都是单个字符串匹配的。
那就是那个next/p数组,叫啥来着?
哦。
最长公共前后缀
(额,我不知道“居中”怎么弄…………………………….)
因为这个“最长公共前后缀”是后面比kmp更高级的“AC自动机”的基础之一,所以要搞懂,很重要。
接下来入正题。
先搞清楚什么事前缀,后缀。
前缀:指一串序列或字符串之类的,除了最后一位,其余前面全部所构成的子序列。
如:字符串I am a pig中,I、I 、I a、I am、………I am a pi,这些都是这个字符串的前缀。(包括空格哦!)
又如:序列123567中,1、12、123、1235、12356都是这个序列的前缀。
后缀:不需要我多说了吧?
如:123中,3、23是后缀。
最长公共前后缀,就是指在一个序列中,所有前缀与所有后缀中,相同的那一部分里,长度最长的那个。
如:1212。
前缀:1,12,121。
后缀:2,12,212。
只有12是相同的,那么最长的公共前后缀就是12,长度为2.
kmp中,那个next/p数组,就是“部分匹配值”数组,里面,p[i]就表示这个序列中,前i位的最长公共前后缀的长度。
如何求呢?
最基础的就是直接暴力从首位枚举+判断,处理这个数组的时间就是接近
然后想了想,如果一个序列有公共前后缀,那肯定是序列的某部分前缀和部分后缀相同嘛,那直接将这序列头和身上任何一个地方去比比就行了,时间就差不多是(n+n)了。
i:=2; while i<=m do //m是该序列长度 begin j:=1; while t[i]<>t[j] do //t是该序列 begin p[i]:=0;//p是上方定义。 inc(i); if i>m then break; end; if i>m then break; k:=0; while t[i]=t[j] do begin inc(k); p[i]:=k; inc(i); inc(j); if i>m then break; end; end;
不过速度倒是没测多少,下面是那些大犇的,超短,原理是啥?
j:=0; for i:=2 to m do begin while (j>0)and(t[j+1]<>t[i]) do j:=p[j]; if t[j+1]=t[i] then inc(j); p[i]:=j; end;
原来,p[i]又指在t[1~i]这个序列中,前p[i]个与后p[i]个是相同的,也就是公共前后缀。那如果t[p[i]+1]=t[i+1],那p[i+1]自然就等于p[i]+1;如果不相等,那p[i+1]就不等于p[i]+1了,(那我们只能尝试p[i+1]能否可以通过p[i]这种情况下里,某一子串得到。也就是看看t[p[p[i]]+1]是否等于t[i+1]了,不行就再往里。)ps:括号内的话,其实我也不是很懂- -||||
再想想吧。
这里是后来加的:
弄这个next数组,实际上就是为下一位i找前面j的位置。
例如t=acabacac这个序列中,例如我们现在i在第8位,j在3位,前7为next为[0,0,1,0,1,2,3],这个数组就是公共前后缀长度,因为t[7]=3,也就表示t[7]=t[3],同理有t[3]=t[1],所以有t[7]=t[1]。在计算下一位时,因为t[8]!=t[4],所以我们要找一个与t[7],t[3]一样的字符,也就是t[1],再判断t[2]?=t[8]。
说到主程序,也就是问题所述从主串里找出匹配串(又叫:模式串),那么就是模式串与主串的匹配过程,这我就不多说了,毕竟上面有链接,不懂去看就行了。
j:=0; for i:=1 to n do //n是主串长度 begin while (j>0)and(t[j+1]<>s[i]) do j:=p[j]; if t[j+1]=s[i] then inc(j); if j=m then begin writeln(i-m+1,' '); j:=p[j]; end; end;
这里主要提及一点,就是那个“j:=p[j]”是怎么来的。
通过上面链接,相比也知道当某一位失配时,该如何做了吧?就是将模式串往后移动一段位置,这段位置怎么求上面也有,这里再给出:“移动距离=已成功匹配数量-成功匹配的部分的部分匹配值”。
从模式串角度看,是它向后移动这么一段距离,但换个角度,会怎样?
从主串上来看,其实是将主串失配的那个字符重新和模式串的一个字符匹配,问题是和哪一个字符匹配?
应该看出来了吧?模式串向后移动了s个位置,那这个失配字符自然是与模式串的失配位置往前移动s个位置的那个字符匹配了。
如果用j表示当前匹配中模式串最后一个匹配成功的位置,s表示应该移动的距离.
那么失配后,j=j-s=j-(j-p[j])=p[j]。这个就是这么来的。
这样一想,这个主程序代码和之前求p的代码神似,再想想,之前求p的代码不就是自己和自己匹配吗?
有点抽象,再想想。
- KMP算法学习小结
- KMP算法小结
- KMP算法小结
- KMP算法小结
- KMP算法小结
- KMP算法小结
- KMP算法小结
- KMP算法小结 2
- kmp算法小结
- KMP算法小结
- KMP算法小结
- KMP算法小结
- KMP算法小结
- KMP算法小结
- KMP算法知识学习
- KMP算法学习
- KMP算法学习笔记
- KMP算法学习
- 邮箱APP个别汉字丢失问题解决
- 面试题
- Springmvc静态资源过滤
- Linux自旋锁与信号量
- java Md5加密工具类
- KMP算法学习小结
- 做个好的专业的程序员立篇
- div页面居中方法
- 杭电2021-发工资咯
- ButterKnife 点击事件没反应的解决方案
- linux服务器的网站日志怎么查看
- Java书写的RAS加密解密
- 实用的iOS面试注意点
- MyEclipse 2015 智能提示 CSS3.0和HTML5的标签