KMP算法(串匹配算法)

串匹配算法

I. 问题描述:
已知两个字符串A,B。字符串长度分别为m,n,且m>n。算法查找并给出B在A中第一次出现的位置。数学描述,即,查找最小的k,使得对于0   i < m,都有A[k+i] = B[i]。
1 输入:

两个字符串A,B。A,B的长度m,n。

2 输出:

B在A中第一次出现的位置。

II. 直接遍历查找:

从A的第一个字符开始,与B的第一个字符比对。若相同则比较两个字符串中的下一位,直至B被完全匹配,或者遇到第一个不匹配字符后,从A的第二个字符开始重复匹配过程。若遇到坏的输入字符串,则算法总开销可达到:O(mn)。该算法的缺陷在于回溯。在每次匹配失败的回溯过程中,该起点k至匹配失败点的所有判断是否相等的信息全部丢失并在之后的匹配中重复比较,使得算法复杂度较高。

III. KMP算法:
1. KMP算法思路

注意到事实:

(1) 字符串B总是需要被多次比较,而其本身的信息却不会随匹配算法的进行改变。

(2) 有价值的核心信息是对于每个字符有最大的i,使得该位前i位子字符串(后缀)与B中的前i位(前缀)相等,当顺位匹配失败时存在这样的关系:A中i位子字符串=匹配失败位前的i位后缀=B的前i位前缀。因此,此时可以跳过B的前i位,直接比较A中该位与B中的i+1位。

基于这样事实的算法可以保证利用到每一次用于匹配的比较信息。

2. 前缀与后缀

前缀和后缀可重叠,但不可完全重叠。即,对于最大后缀长度l,0  k < l,B[k] = B[i-l+k],且l-1 != i-1。

3. 表next的引入

为了记录每个字符的最大后缀长度,构造一个表next,表的大小为n,next[i]即为B[i]的最大后缀长度,规定next[0] = -1,next[1] = 0。因此,当A[j]与B[i]发生不匹配时,则比较A[j]与B[next[i]]。因为在之前的next表构造与A,B匹配过程中,已获得以下信息:0  k < next[i],A[j-k] = B[i-next[i]+k] = B[k]。

4. 表next的构造

表next的构造使用归纳法。

next[0] = -1, next[1] = 0为归纳基础,已知0,1,2,...,i-1的next值,下计算next[i]。

首先比较B[i-1]与B[next[i-1]],若B[i-1] = B[next[i-1]],则next[i] = next[i-1] +1。

若B[i-1] != B[next[i-1]],则对比i-1的后缀与前缀。对于0  k < next[i-1],B[k] = B[i-1-next[i-1]+k]。考虑B[next[i-1]]的后缀,利用两个后缀next的性质,有0  k < next[next[i-1]],B[k] = B[next[i-1]-next[next[i-1]]+k] = B[i-1-next[i-1]+k] = B[i-1-next[next[i-1]]+k],因为B[next[i-1]]的最大后缀长度的性质导致B[next[i-1]-next[next[i-1]]] = B[i-1-next[next[i-1]]]一定不能同之后的字符构成更长的后缀(否则与next[next[i-1]]为next[i-1]的最大后缀长度矛盾)。因此,问题转化为只需比较B[i-1]与B[next[next[i-1]]]即可。

算法复杂性:因为B中每一位字符的next值只需最多两次比较即可确定,因此总的算法复杂性为:O(n)。

5. 算法描述

首先对于输入的字符串B,构造表next。从A的第一个字符开始,与B的第一个字符比对。若相同则比较两个字符串中的下一位,直至B被完全匹配,或者遇到第一个不匹配字符后,比较A该位字符与B[next[i]]。若相同则继续比较两个字符串中的下一位,若不匹配,则比较A该位字符与B[next[next[i]]],以此类推。

6. 算法复杂性

若在B的第i位处发生不匹配,则最多要回溯i次到达B的第一位重新开始顺位匹配。而在该位发生不匹配之前,至少进行了i次成功的匹配。因此,可将该回溯时间平摊在成功匹配的时间上。因此,对于A中每一位字符,运行时间都是O(1)。又由于KMP算法对A线性遍历不进行回溯,因此匹配过程总的算法复杂性为:O(m)。

总算法复杂性:KMP算法总的时间开销为构造next的时间复杂性+匹配过程的时间复杂性:O(m+n)。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值