KMP算法

参考文档: http://jakeboxer.com/blog/2009/12/13/the-knuth-morris-pratt-algorithm-in-my-own-words/

 http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html

字符串模式匹配

        串的模式匹配,是求第一个字符串(模式串)在第二个字符串(主串)中的位置。

       例如: 图1

      简单的模式匹配算法是:从主串S第一个字符开始和模式串T的第一个字符比较,若相等,则继续逐个比较后续字符,直到T中的每个字符依次和S中的一个连续的字符序列相等,则匹配成功;如果比较过程中有某对字符不相等,则从主串S的下一个字符起再重新和T的第一个字符比较。如果S中的字符都比完了仍然没有匹配成功,则匹配不成功。
         该算法的时间复杂度为O(n*m), n、m分别是主串和模式串的长度.

         有大牛觉得这算法效率太低,没有充分利用模式串的特点,于是想出来KMP算法。

KMP算法

         我们说KMP算法要充分利用模式串的特点,那么模式串的特点是什么?然后一个怎么利用?

举个例子: 图2

       

        在该例中,模式串的第5个与主串的第7个匹配时发现不一致(这时我们是知道主串的第3~第6个字符是什么)。如果按照我们之前说的简单匹配算法,这时应该让模式串的第一个字符(a)与主串的第4个字符(b)比较。然而我们为什么要这样做,在上一步匹配时我们其实以及知道了主串的第四个字符是b,第6个字符是a,我们为什么不直接从主串的第6个字符开始比较?这就是KMP算法考虑的地方。

          我们人是可以直接用眼睛看出模式串的特点,然而计算机木有眼睛,于是总得有个东西告知程序,于是便有了部分匹配表。

The Partial Match Table(部分匹配表):

         部分匹配表,顾名思义,是记录模式串与主串部分匹配时候的信息,这是KMP算法的关键。

         先介绍几个概念:

      前缀和后缀。

         对于上图中的模式串"abcac",该字符串的前缀有:a,ab,abc,abca;后缀有:c,ac,cac,bcac。

         部分匹配表的值就是前后缀中最大相同子串的长度。没有则为0.

         例如:字符串“ababa”.其前缀有:a,ab,aba,abab;后缀有:a,ba,aba,baba。最大相同子串为aba。

       我们定义数组table[ ],用于存放部分匹配表的值,为了让下标与字符串长度对应,我们让table[0]不存放任何有意义的数,该例中我们存放0。table[1]表示字符串“ababa”的子串“a”的部分匹配表的值,table[2]表示子串“ab”的部分匹配表的值......;则table[5]对应于该字符串"ababa"的值为3.那么对于该字符串“ababa”,table[ ]的值应该为{0,0,0,1,2,3 }。

          那么模式串“abcac”对应的部分匹配表的指为{0,0,0,0,1,0}。这些值的意义何在?该怎么使用?

         如图2所示,比较到模式串的第5个字符时不成功,即表示前4个是成功的(相等的),那么我们应该看部分匹配表中索引为4的数(因为我们让索引0不存放有意义的数据),即1;1表示模式串匹配不成功的前一个字符是和第一个字符一样的,(如果是2就表示匹配不成功的前两个字符是和第一二字符一样的)。那么我们应该将模式串直接移动到与该串第一个字符相同的位置,移动的宽度为5-1-1(5表示的是第几个字符匹配不成功;第一个1表示前面的(5-1)个字符匹配成功了;第二个1是部分匹配表的数值,表示最大相同字串的长度)。于是图2所示例子中我们应该从3+(5-1-1)=6的字符出开始比较。

     这就是KMP算法的思想了。水平有限,有什么理解错误之处,还望大家积极指出。      

     第一次写博客,谢谢大家。共勉。

  

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值