KMP算法的正确性证明及一个小优化
直接把作业帖上来是不是有点不太公道呀。。。
无所谓啦反正各位看着开心就行
KMP算法
对于模式串$P$,建立其前缀函数$ N$ ,其中$N [q] $ 表示在$P$中,以$q$位置为结束的可以匹配到前缀的最长后缀的长度(也可以理解为那个前缀的结束位置),在匹配中,若$P[i]$与$S[j]$失配,则令$i=N [i-1] +1$ ,否则$i=i+1,j=j+1$
现考虑如何构造$N$ ,设当前以计算出$N[1..i-1]$ ,则令$k=N[i-1]$ ,若 $P[k+1]=P[i]$,则令$N[i]=k+1$ ,否则令$k=N[k]$ 。重复上述过程,直至找到$N[i]$
可证该算法能在$\Theta(|P|) $ 的时间内构造出前缀函数$N$ ,在$\Theta (|S|)$ 的时间内完成匹配,总的时间复杂度为$\Theta(|S|+|P|)$
KMP算法的正确性证明
先证明匹配过程的正确性:
在过程中,若$P[1..q]$ 与$S[s+1...s+q]$ 匹配,而$P[q+1]$与$S[s+q+1]$ 失配,那么由$N$的定义可立即得出$P[1..N[q]]$ 与 $S[s+q-N[q]+1...s+q]$ 匹配,而$S[1...t]$与$S[s+q-t+1...s+q]$ 失配$(N[q]<t<q)$ ,即只需检验$P[N[q]+1]$ 与$S[s+q+1]$ 的匹配情况即可,匹配过程的正确性即可得证。
接下来证明前缀函数$N$计算的正确性:
令$N^*[q]= \{N[q],N^{(2)}[q],…,N^{(t)}[q]\}$ 其中$N^{(t)}[q]=N^{(t-1)}[q],N^{(0)}[q]=N[q]$ ,那么$N^*[q]$ 为以q位置为结束的可以匹配到前缀的后缀的所有长度(即匹配到所有前缀的位置),同时有$N[q]-1\in N^*[q-1]$ ,因此只需从大到小枚举$N^*[q-1]$ 中的元素并通过判断即可得出$N[q]$ 。
KMP算法的时间复杂度证明
在匹配时:$i,j$增长了$|S|$ ,而在$i=N[i-1]+1$ 中,$i$ 至少减少1,即该语句至多执行了$|S|$次,因此时间复杂度为$\Theta(|S|)$。
构造前缀函数$N$ 时: 我们考虑k的变化,我们可以得到,在每次$k=N[k]$ 中,$k$ 至少减少1,又因为$k$随$i$增加了$|P|$次,即该语句至多执行$|P|$ 次,因此时间复杂度为$\Theta(|P|)$ 。
因此总的时间复杂度为$\Theta(|S|+|P|)$ 。
KMP算法的优化
我们希望通过优化,为了减少失配的概率,因此提出如下改进:
在构造$N'$数组时,当$P[k+1]=P[i]$ 时,若$P[i+1]=P[k+2]$ 则$N'[i]=k+1$ 否则$N'[i]=N'[k+1]$ 。
该优化的正确性证明
在匹配时,我们发现,若$P[q+1]$ 与$S[s+q+1]$失配,同时$P[q+1]=P[N^{(t)}[q]+1]$ ,则$P[N^{(t)}[q]+1]$一定与$S[s+q+1]$ 失配,因此若$P[N[q]+1]=P[q+1]$ ,则该比较一定失配,无需考虑。
在该优化中,由该函数的递归求法可得,$N'[q]=max\{N^*[q]且P[q+1]\neq P[N^{(t)}[q]+1]\}$ ,因此$N'[q]$ 依旧能枚举完所有可能匹配的前缀,同时减少失配概率。
该优化对算法空间与时间复杂度的影响
由于该优化只是改变了N数组的构造方法,因此对空间复杂度无影响。
时间复杂度的证明同KMP的证明,可得对最坏情况下的时间复杂度无影响
由于该算法避免了出现$P[N[q]+1]=P[q+1]$的情况,因此对于有较多重复子串的模式串有较好的优化效果(如aaaab,abcabcabcd)
KMP算法的正确性证明及一个小优化的更多相关文章
- KMP算法Next()函数的一个应用
转载:http://www.cnblogs.com/vongang/archive/2012/05/04/2483419.html 记一个KMP算法的应用,经典的KMP算法详解还是看这里 问题:给一个 ...
- kmp算法 汇总
来源:http://blog.csdn.net/qq_34494458/article/details/75253466 KMP算法,是由Knuth,Morris,Pratt共同提出的模式匹配算法,其 ...
- 真正理解KMP算法
作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4403560.html 所谓KMP算法,就是判断一个模式串是否是一个字符串的子串,通常的算法当 ...
- KMP算法——从入门到懵逼到了解
本博文參考http://blog.csdn.net/v_july_v/article/details/7041827 关于其它字符串匹配算法见http://blog.csdn.net/WINCOL/a ...
- (原创)白话KMP算法详解
引子:BF暴力算法 KMP算法知名度相当高,燃鹅其理解难度以及代码实现对于初学数据结构和算法的同学并不友好,经过两天的总结,详细总结KMP算法如下: 初学串的模式匹配时,我们都会接触到,或者说应该能想 ...
- KMP算法的改进
KMP算法的改进 KMP算法已经在极大程度上提高了子符串的匹配效率,但是仍然有改进的余地. 1. 引入的情景 下面我们就其中的一种情况进行分析: 主串T为"aaaabcde-" 子 ...
- KMP算法解析(转自图灵社区)
KMP算法是一个很精妙的字符串算法,个人认为这个算法十分符合编程美学:十分简洁,而又极难理解.笔者算法学的很烂,所以接触到这个算法的时候也是一头雾水,去网上看各种帖子,发现写着各种KMP算法详解的转载 ...
- BZOJ 1009 HNOI2008 GT考试 KMP算法+矩阵乘法
标题效果:给定的长度m数字字符串s.求不包括子s长度n数字串的数目 n<=10^9 看这个O(n)它与 我们不认为这 令f[i][j]长度i号码的最后的字符串j位和s前者j数字匹配方案 例如,当 ...
- 串的模式之kmp算法实践题
给定两个由英文字母组成的字符串 String 和 Pattern,要求找到 Pattern 在 String 中第一次出现的位置,并将此位置后的 String 的子串输出.如果找不到,则输出“Not ...
随机推荐
- web前端面试第三波~
快来测试测试自己掌握能力吧! 1. class.forname的作用?为什么要用? 1).获取Class对象的方式:类名.class.对象.getClass().Class.forName(" ...
- Python关键字yield的解释
yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器. >>> def createGenerator() : ... mylist = range(3) . ...
- SQL之left join、right join、inner join
创建表(Create table): CREATE TABLE A ( Id INT PRIMARY KEY, Name VARCHAR(20) NOT NULL); CREATE TABLE B ( ...
- vim设置注意记录
set vb t_vb= setlocal buftype = "解决不能保存buff错误
- 各种浏览器开启JavaScript脚本方法
各种浏览器开启JavaScript脚本方法 随着网站设计技术的发展,为了用户友好体验,大部分网站使用了JavaScript脚本设计,如果您的浏览器禁用或关闭的JavaScript支持,那么可能造成网站 ...
- 用 NodeJS 实现 BigPipe
BigPipe 是 Facebook 开发的优化网页加载速度的技术.网上几乎没有用 node.js 实现的文章,实际上,不止于 node.js,BigPipe 用其他语言的实现在网上都很少见.以至于这 ...
- Canvas 颜色反转
ImageData中的元素反转颜色 255-data[i,i+1,i+2] <!DOCTYPE html> <html lang="en"> <hea ...
- Rabbitmq无法监听后续消息
现象: 消息队列在处理完一条消息后,无法继续监听后续消息. 首先,系统启动时要启动接收方法如下: protected void Application_Start() { RouteTable.Rou ...
- 爱你不容易 —— Stream详解
作为前端,我们常常会和 Stream 有着频繁的接触.比如使用 gulp 对项目进行构建的时候,我们会使用 gulp.src 接口将匹配到的文件转为 stream(流)的形式,再通过 .pipe() ...
- Ubuntu安装搜狗拼音
p { margin-bottom: 0.25cm; direction: ltr; color: rgb(0, 0, 0); line-height: 120% } p.western { font ...