经典模式匹配算法

本文介绍了模式匹配算法,特别是KMP算法。KMP算法避免了在匹配失败时的主串回溯,通过计算next数组来确定下次匹配的起始位置。文章通过递推方式解释了next数组的生成,并提供了C++代码实现。最后,讨论了KMP算法的改进,优化了模式匹配的效率。

模式匹配算法的代码只有十四行,看了两天,终于看懂了,吐槽一下,算法太经典了。

首先要了解一下串操作中模式匹配算法的作用是什么,简单的说就是从一个主串中需找特定的字符子串,要寻找的字符子串称为模式串。自然很容易想到一个方法就是:直接拿模式串在主串中移动,一旦移动到某一个位置模式子串所有的字符与主串中的字符都相同,那么就找到了字符串,该方法成为FM算法。记主串为s1s2……sn,模式串为p1p2……pm。如图一所示:

 

图一:FM算法串匹配

这种算法很简单,但是时间上付出了很大的代价,每一次匹配不成功,都必须回溯到原来的位置的下一个位置重新匹配,复杂度为O(m*n)。模式串匹配是在该方法的基础之上进行改进,想办法不需要在主串中回溯,即希望主串中每个字符值匹配一次,KMP算法是可以做到的,下面我们就来看看KMP

假设拿模式串和主串进行匹配,从模式串的第一个字符开始,如果相等,则进行下一个字符的比较……一直进行下去直到两个字符不等,记录此时主串位置为i,模式串位置为j,即第i和第j个位置失配。这样我们想办法让主串的i保持不回溯,其实如果’pj-k+1pj-k+2……pj-1’=’p1p2……pk-1’(在j之前:前缀=后缀,注意这里前后缀相等的长度要取最大值),只需将模式串右移,(令next[j]=k)就可以保持i不回溯了(注意这里我们讨论从第一个字符串开始,不考虑0下标的数组)。如图二所示:

 

图二:KMP模式串匹配

总结起来KMP算法与FM算法的不同就是,FM在失配时需要回溯,而KMPi-j失配时不需要回溯,只需确定新的k,使得下一次next[j]=k,重新进行匹配,一直这样下去……确定k的准则就是j之前的:前缀等于后缀pj-k+1pj-k+2……pj-1’=’p1p2……pk-1’。

下面就来谈谈模式串如何用代码实现前缀等于后缀找next[j]=k。请跟上节奏,有点绕:

因为每一个位置都有一个next值,于是可以做如下假设:设模式串第i个位置的next[j]=k,即有:

‘pj-k+1pj-k+2……pj-1’  =  ’p1p2……pk-1’              (1

接下来看一下next[j+1]如何取值?

1)如果pj=pk,则表明

’pj-k+1pj-k+2……pj-1pj’  =  ’p1p2……pk-1pk’            (2

所以next[j+1]= next[j]+1= k+1

2)如果pj != pk,则表明

‘pj-k+1pj-k+2……pj-1’  =  ’p1p2……pk-1’             (3

pj  !=  pk                                  (4

用下图不同颜色表示相等的前缀和后缀

 

图三 :模式串示意图

这时候主模式串又可以看做自己的模式串,即拿自身的前缀去找相同的后缀。由于已经有(3)和(4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值