经典算法题每日演练——第七题 KMP算法
在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的,
确实kmp算法还是有点饶人的,如果说红黑树是变态级的,那么kmp算法比红黑树还要变态,很抱歉,每次打kmp的时候,输
入法总是提示“看毛片”三个字,嘿嘿,就叫“看毛片算法”吧。
一:BF算法
如果让你写字符串的模式匹配,你可能会很快的写出朴素的bf算法,至少问题是解决了,我想大家很清楚的知道它的时间复
杂度为O(MN),原因很简单,主串和模式串失配的时候,我们总是将模式串的第一位与主串的下一个字符进行比较,所以复杂
度高在主串每次失配的时候都要回溯,图我就省略了。
二:KMP算法
刚才我们也说了,主串每次都要回溯,从而提高了时间复杂度,那么能不能在“主串”和“模式串”失配的情况下,主串不回溯呢?
而是让”模式串“向右滑动一定的距离,对上号后继续进行下一轮的匹配,从而做到时间复杂度为O(M+N)呢?所以kmp算法就是
用来处理这件事情的,下面我们看下简单的例子。
通过这张图,我们来讨论下它的一般推理,假设主串为S,模式串为P,在Si != Pj的时候,我们可以看到满足如下关系式
Si-jSi-j+1...Sn-1=P0P1..Pj-1。那么模式P应该向右滑动多少距离?也就是主串中的第i个字符应与模式串中的哪一个字符进行比较?
假设应该与模式串中的第k的位置相比较,假如模式串中存在最大的前缀真子串和后缀真子串,那么有P0P1..Pk-1=Pj-kPj-k+1...Pj-1.
这句话的意思也就是说,在模式P中,前k个字符与j个字符之前的k个字符相同,比如说:“abad”的最大前缀真子串为“aba",最大
后缀真子串为“bad”,当然这里是不相等,这里的0<k<j,我们希望k接近于j,那么我们滑动的距离将会最小,好吧,现在我们用
next[j]来记录失配时模式串应该用哪一个字符于Si进行比较。
设 next[j]=k。根据公式我们有
-1 当j=0时
next[j] = max{k| 0<k<j 且 P0P1..Pk-1=Pj-kPj-k+1...Pj-1}
0 其他情况
好,接下来的问题就是如何求出next[j],这个也就是kmp思想的核心,对于next[j]的求法,我们采用递推法,现在我们知道了
next[j]=k,我们来求next[j+1]=?的问题?其实也就是两种情况:
①:Pk=Pj 时 则P0P1...Pk=Pj-kPj-k+1...Pj, 则我们知:
next[j+1]=k+1。
又因为next[j]=k,则
next[j+1]=next[j]+1。
②:Pk!=Pj 时 则P0P1...Pk!=Pj-kPj-k+1...Pj,这种情况我们有点蛋疼,其实这里我们又将模式串的匹配问题转化为了上面我们提到
的”主串“和”模式串“中寻找next的问题,你可以理解成在模式串的前缀串和后缀串中寻找next[j]的问题。现在我们的思路就是一定
要找到这个k2,使得Pk2=Pj,然后将k2代入①就可以了。
设 k2=next[k]。 则有P0P1...Pk2-1=Pj-k2Pj-k2+1...Pj-1。
若 Pj=Pk2, 则 next[j+1]=k2+1=next[k]+1。
若 Pj!=Pk2, 则可以继续像上面递归的使用next,直到不存在k2为止。
好,下面我们上代码,可能有点绕,不管你懂没懂,反正我懂了。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SupportCenter.Test 7 { 8 public class Program 9 { 10 static void Main(string[] args) 11 { 12 string zstr = "ababcabababdc"; 13 14 string mstr = "babdc"; 15 16 var index = KMP(zstr, mstr); 17 18 if (index == -1) 19 Console.WriteLine("没有匹配的字符串!"); 20 else 21 Console.WriteLine("哈哈,找到字符啦,位置为:" + index); 22 23 Console.Read(); 24 } 25 26 static int KMP(string bigstr, string smallstr) 27 { 28 int i = 0; 29 int j = 0; 30 31 //计算“前缀串”和“后缀串“的next 32 int[] next = GetNextVal(smallstr); 33 34 while (i < bigstr.Length && j < smallstr.Length) 35 { 36 if (j == -1 || bigstr[i] == smallstr[j]) 37 { 38 i++; 39 j++; 40 } 41 else 42 { 43 j = next[j]; 44 } 45 } 46 47 if (j == smallstr.Length) 48 return i - smallstr.Length; 49 50 return -1; 51 } 52 53 /// <summary> 54 /// p0,p1....pk-1 (前缀串) 55 /// pj-k,pj-k+1....pj-1 (后缀串) 56 /// </summary> 57 /// <param name="match"></param> 58 /// <returns></returns> 59 static int[] GetNextVal(string smallstr) 60 { 61 //前缀串起始位置("-1"是方便计算) 62 int k = -1; 63 64 //后缀串起始位置("-1"是方便计算) 65 int j = 0; 66 67 int[] next = new int[smallstr.Length]; 68 69 //根据公式: j=0时,next[j]=-1 70 next[j] = -1; 71 72 while (j < smallstr.Length - 1) 73 { 74 if (k == -1 || smallstr[k] == smallstr[j]) 75 { 76 //pk=pj的情况: next[j+1]=k+1 => next[j+1]=next[j]+1 77 next[++j] = ++k; 78 } 79 else 80 { 81 //pk != pj 的情况:我们递推 k=next[k]; 82 //要么找到,要么k=-1中止 83 k = next[k]; 84 } 85 } 86 87 return next; 88 } 89 } 90 }
经典算法题每日演练——第七题 KMP算法相关推荐
- 经典算法题每日演练——第六题 协同推荐SlopeOne 算法
原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法 相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,"商品推荐","猜你喜欢&quo ...
- 经典算法题每日演练——第十题 树状数组
原文:经典算法题每日演练--第十题 树状数组 有一种数据结构是神奇的,神秘的,它展现了位运算与数组结合的神奇魅力,太牛逼的,它就是树状数组,这种数据结构不是神人是发现不了的. 一:概序 假如我现在有个 ...
- 经典算法题每日演练——第三题 猴子吃桃
猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个.第二天早上又将剩下的桃子吃了一半,还是不过瘾又多 吃了一个.以后每天都吃前一天剩下的一半再加一个.到第10天刚好剩一个.问猴子第一天摘了多 ...
- 经典算法题每日演练——第十一题 Bitmap算法
在所有具有性能优化的数据结构中,我想大家使用最多的就是hash表,是的,在具有定位查找上具有O(1)的常量时间,多么的简洁优美, 但是在特定的场合下: ①:对10亿个不重复的整数进行排序. ②:找出1 ...
- 经典算法题每日演练——第五题 字符串相似度
原文地址:http://www.cnblogs.com/huangxincheng/archive/2012/11/11/2765633.html 这篇我们看看最长公共子序列的另一个版本,求字符串相似 ...
- 经典算法题每日演练——第二十一题 十字链表
上一篇我们看了矩阵的顺序存储,这篇我们再看看一种链式存储方法"十字链表",当然目的都是一样,压缩空间. 一:概念 既然要用链表节点来模拟矩阵中的非零元素,肯定需要如下5个元素(ro ...
- 经典算法题每日演练——第二十二题 奇偶排序
原文:经典算法题每日演练--第二十二题 奇偶排序 这个专题因为各种原因好久没有继续下去了,MM吧...你懂的,嘿嘿,不过还得继续写下去,好长时间不写,有些东西有点生疏了, 这篇就从简单一点的一个&qu ...
- 经典算法题每日演练——第十九题 双端队列
经典算法题每日演练--第十九题 双端队列 原文:经典算法题每日演练--第十九题 双端队列 话说大学的时候老师说妹子比工作重要~,工作可以再换,妹子这个...所以...这两个月也就一直忙着Fall in ...
- 经典算法题每日演练——第一题 百钱买百鸡
经典算法题每日演练--第一题 百钱买百鸡 原文:经典算法题每日演练--第一题 百钱买百鸡 百钱买百鸡的问题算是一套非常经典的不定方程的问题,题目很简单:公鸡5文钱一只,母鸡3文钱一只,小鸡3只一文钱, ...
最新文章
- Linux内核--异常和中断的区别
- 用Linux Shell脚本轻松管理Radius服务器
- Android——四大组件、六大布局、五大存储
- 火狐查cookie_Firefox 65默认会阻止跟踪Cookie
- c语言编程题2^0+2^1+……+2e63,牛客网刷题33(2道题)
- JAVA的字符串拼接与性能
- linux上使用netstat查看当前服务和监听端口
- 伯克利的云计算报告(中)
- Sql代码美化工具:Sql Pretty Printer for SSMS V3.6.1
- [百晓生]-鼠标右键新建添加RTF文档
- IDEA跟金山词霸的小bug
- linux 连接打印机
- 数据库设计三大范式原则
- MATLAB人工神经网络的手写数字识别系统
- python3程序下载安装_Python3 环境搭建
- Unity3D跑酷游戏开发-无尽的道路 (原创教程)
- 融资、量产和一栈式布局,这家Tier 1如此备战高阶智驾决赛圈
- 学画画要花多少钱_高二学美术的费用大概是多少 要花多少钱
- python获取中文拼音首字母以进行检索
- python电梯题_OO——电梯作业总结