KMP算法学习

KMP算法

       一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此称之为KMP算法。其基本思路是,在字符串匹配的过程中,不会退目标字符串的指针,而是回退模式串的指针。如当目标字符串的第i,i+1, ..., i+k位置的字符与模式串第0, 1, ..., k位置的字符相同,但是目标字符串的第i+k+1处与模式串第k+1处不相同时,目标字符串的指针不需要回退到i+1,而是回退模式串的指针,用目标串第i+k+1处与模式串回退的位置开始重新比较。模式串回退到什么位置,取决于模式串前k个字符,因此在KMP算法中定义了一个next(int)函数,用于得到记录模式串每个字符对应的回退位置,即当模式串匹配到k处不相等时,模式串回退到next(k)处。

       对应next(int k)函数的思路,我的理解是对于模式串的前k个字符组成的字符子串,例如假设为abcabc,该子串的前j个字符是该子串的后缀,则next(k) = max{ j },在例子中next()函数值为3。例如,如果目标串为A = ****abcabce****, 模式串为B = abcabcd,当匹配到目标串的e处时,如下

A : ****abcabce****

B :      abcabcd

此时不相等,回退目标串,回退到B[3]的位置,而不用回退到B的第一个字符处。如下

A : ****abcabce****

B             abcabcd

通过KMP算法中next函数的计算,模式串B对应的回退数组为[0,0,0,1,2,3,0]。


总结

      KMP算法的时间复杂度是O(n+m),它需要提前计算模式串的回退数组。而一般的硬匹配,或者说暴力匹配,其时间复杂度是O(n*m)。但是当我查看Java的String类时,令人疑惑的事发生了,String类中有一个static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex)方法,用于进行字符数组的匹配,而Java的设计者是使用硬匹配的方式进行比较匹配的,按理说使用KMP算法,其效率应该更高些,比较其时间复杂度要小些。

      通过代码测试发现,在一般字符串匹配比较中,使用硬匹配的方式进行字符串的匹配,其所花的时间要小于KMP算法。但是当模式串中出现大量重复的子串,并且目标串中也出现了大量与模式串中重复子串相同的子串时,KMP算法匹配所花的时间要小些。

      仔细一想,原来如果模式串中没有重复字符时,其回退数组的值全为0,因此其跟硬匹配的匹配效果是一样的,而KMP算法还要花额外的时间来计算回退数组的值。而当模式串和目标串中都有大量相同的子串重复出现时,回退数组的使用省掉了一些不必要的比较,而当大量重复子串的出现会使得回退省下的时间比计算回退数组要多得多的时候,KMP算法就显现出其优势了。因此我觉得KMP算法只是比较适合在一些特殊字符串匹配的情况下使用。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值