字符串匹配常用算法

      字符串匹配(string match)是在实际工程中经常会碰到的问题,通常其输入是原字符串(String)和子串(又称模式,Pattern)组成,输出为子串在原字符串中的首次出现的位置。通常精确的字符串搜索算法包括暴力搜索(Brute force),KMP, BM(Boyer Moore), sunday, robin-karp 以及 bitap。下面分析这几种方法并给出其实现。假设原字符串长度M,字串长度为N。

1. Brute force.

该方法又称暴力搜索,也是最容易想到的方法。

预处理时间 O(0)

匹配时间复杂度O(N*M)

主要过程:从原字符串开始搜索,若出现不能匹配,则从原搜索位置+1继续。

 

 

2,KMP.

KMP是经典的字符串匹配算法。

预处理时间:O(M)

匹配时间复杂度:O(N)

主要过程:通过对字串进行预处理,当发现不能匹配时,可以不进行回溯。

 

注意:在预处理中,表面看起来时间复杂度为O(N^2),但是为什么是线性的,在时间复杂度分析中中,通过观察变量的变化来统计零碎的、执行次数不规则的情况,这种方法叫做摊还分析。我们从上述程序的j 值入手。每一次执行上述循环预处理语句中的第二个else时都会使j减小(但不能减成负的),而另外的改变j值的地方只有一处。每次执行了这一处,j都只能加1;因此,整个过程中j最多加了M-1个1。于是,j最多只有M-1次减小的机会(j值减小的次数当然不能超过M-1,因为j永远是非负整数)。这告诉我们,while循环总共最多执行了M-1次。按照摊还分析的说法,平摊到每次for循环中后,一次for循环的复杂度为O(1)。整个过程显然是O(M)的。另外关于KMP的详细分析,可以参考Matrix67KMP算法详解

 

3,Boyer Moore

Boyer Moore是字符串匹配算法中的经典,可以参考论文a faster string searching algorithm。

预处理时间O(N + M^2)

匹配时间复杂度O(N)

主要过程:通过预处理原字符串以及待匹配字串,从而在匹配失败时可以跳过更多的字符。

 

提示:该算法主要利用坏字符规则和好后缀规则进行转换。所谓坏字符规则,是指不能匹配时的字符在待匹配字串中从右边数的位置;而好后缀规则则是指子串中从该不匹配位置后面所有字符(都是已匹配字符)再次在字串中出现的位置(k),其中s[k,k+1,---,k+len-j-1] = s[j+1, j+1,---,len-1], 并且s[k-1] !=  [j] || s[k-1] = $, 其中$表示增补的字符,可以与任何字符相等。

举例来说,对于字串ABCXXXABC

   -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9

A B C X X X A B C

j=9 9//NULL->其值为当前位置。

j=8 $ 0     //C->虽然出现在3,但[2] = [j],所以不满足

j=7 $ $ -1    //BC出现在开始[2],但[1]=[j]

j=6 1    //ABC

j=5 $ 0    //XABC

j=4 $ $ -1    //XXABC

j=3 $ $ $ -2  //XXXABC

j=2 $ $ $ $ -3  //CXXXABC

j=1 $ $ $ $ $ -4   //BCXXXABC

 

4, Sunday

Sunday算法比较简单,其实就是利用Boyer Moore中的坏字符规则,实现起来简单,效果也还不错。

预处理时间O(M)

匹配时间复杂度O(N*M)

 

 

5, Robin-Karp

Robin-Karp主要利用HASH函数来处理字串,从而完成匹配。

预处理时间O(0)

最坏匹配时间复杂度O(N*M)

 

注意:主要依赖于hash函数的设计。

 

6, Bitap

Bitap算法主要利用位运算进行字符串的匹配,其匹配过程可以看作是有穷自动机中状态的转换,按照字串(pattern)的连续分解状态进行转换,从而到达终点,此时匹配过程完成。

预处理时间O(M)

最坏匹配时间复杂度O(N*M)

 

注意:Bitap匹配算法中可以改用位移操作实现,从而将匹配复杂度从O(N*M)降低到O(N)。

 

总结,以上算法中,性能较好的为KMP,BM, 实现简单的为BF,Sunday,Bitap。两者折中来看,KMP表现较好。

预处理时间 匹配时间复杂度

BF O(0) O(N*M)

KMP O(M) O(N)

BM O(N+M^2) O(N)

Sunday O(M) O(N*M)

Robin-Karp O(0) O(N*M)

Bitap O(M) O(N*M)->O(N)

 

以上六种算法比较实现的代码如下所示(其中string长度10000)。

  • 0
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值