KMP算法分析

KMP算法通过部分匹配表避免了传统模式匹配中的回溯问题,提高效率。当主串与模式串字符不匹配时,模式串会根据next数组滑动到适当位置继续比较。next数组的计算依赖于模式串自身,它表示了模式串中前缀和后缀的最大公共长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符串比较算法(i是主串的比较指针,j是子串比较指针)
这里写图片描述

传统算法

逐个比较,遇到不同的字符回溯 i 。存在 i 的回溯问题,如上图所示

KMP算法

改进了传统的算法:每当一趟匹配过程中出现字符比较不等时,不需要回溯i指针,而是利用“部分匹配”的结果将模式向右“滑动”尽可能远的距离后,继续比较。
如图所示,从传统比较的第三趟部分可知,主串中第4、5、6个字符必然是 b c a(即模式串中第2、3、4个字符)所以可以向后滑动3个位置后继续比较,即进行i=7,j=2时的字符串比较即可。同理,在第一趟匹配出现字符不等时,仅需要将模式向右移动两个字符的位置继续进行i=3,j=1时的比较。
现在讨论一般情况。假设
+ 主串为”s1 s2 … sn”
+ 模式串为”p1 p2 … pn”

为了改进上述的传统算法,我们需要知道“当主串中第 i 个字符与模式串中的 第j 个字符“失配”时,主串中的第i个字符(i指针不回溯)应该与模式串中的那个字符进行比较?”
假设此时应该与第 k(k<j) 个字符进行比较,则模式串中的前 k-1 个字符与子串必须满足下列关系(1)
这里写图片描述
从已经得到的部分匹配结果可知(2)
这里写图片描述
由(1)和(2)可推出(3)
这里写图片描述

主串    a b a b c a b c a c b a b
模式串  a b c a c
如上:当i=7,j=5时出现了失配,我们分析
1)当k=2时
公式(1)满足 p1 = p6 即 a = a
公式(2)满足 p4 = s6 即 a = a
即 p1=p4
2)当k=3时
公式(1)满足 p1 p2 = s5 s6 但是a b != c a
公式(2)满足 p3 p4 = s5 s6 即 c a = c a
即 p1p2 != p3p4
3)当k=4时
公式(1)满足 p1 p2 p3 = s4 s5 s6,但是 abc!=bca,所以k!=4
即 p1 p2 p3 != p2 p3 p4
要求k<j所以k的最大值为2
即 k=2,也就是当i=7,j=5时失配后,主串中i=7的位置的字符 b 应该与子串中的第 k(k=2)个字符 b进行比较。

由上可知,若模式串中存在满足式(3)的两个子串,则当匹配过程中,主串中第 i 个字符与模式串中第 j 个字符比较不等时,仅需要将模式串向右滑动到模式串中第 k 个字符去和主串中第 i 个字符对齐,此时,模式串中前k-1个字符的子串必满足公式(1)。由此,匹配仅需从模式串中第 k 个字符与主串中第 i 个字符比较起继续进行。
若另next[j]=k,则 next[j]表明当模式中第j个字符与主串中相应的字符“失配”时,在模式找那个需要重新和主串中该字符进行比较的字符位置。由此可引出模式串的next函数的定义:
这里写图片描述

next[j]=k 为 next[5] = 2

由此可推出下列模式串的next函数值:
这里写图片描述
从上述的分析可知,模式串的next数组取决于模式串本身,和相匹配的的主串没有关系.
由定义可知 next[1]=0
设 next[j] = k,表明在模式串中存在下列关系,其中 1<k<j:
这里写图片描述
此时 next[j+1] = ?可能存在两种情况:
+ 若 pk = pj,则表示模式串中‘p1 … p’ = ‘pj-k+1 … pj’,此时 next[j+1] = next[j]+1;
+ 若 pk != pj ,则表示模式串中‘p1 … pk’ != ‘pj-k+1 … pj’,此时可以把求next函数值的问题看成是一个模式匹配的问题,整个模式串既是主串又是模式串,而当前的匹配过程中,已有 ‘p1 … pk-1’ = ‘pj-k+1 … pj-1’,则当pj!=pk时应将模式串向右滑动至以模式中的第 next[k]个字符串中的第j个字符相比较,若next[k] = k’,且 pj = pk’,则说明在主串中第 j+1 个字符之前存在一个长度为 k’(即 next[k])的最长子串,和模式串中从首子符长度为 k’ 的子串相等,即满足(4)
这里写图片描述
这就是说 next[j+1] = k’+1 即* next[j+1] = next[k]+1*
同理,如 pj != pk’,则将模式继续向右滑动直至将模式中第 next[k’]个字符和pj对齐,。。。,依次类推,知道 pj 和模式中某个字符匹配成功或者不存在任何 k’(1<k’<j)满足(4),则next[j+1]=1

例如,图中已求得前6个字符的next函数值,现求next[7],因为next[6]= 3,又有 p6!=p3,则比较p6和p1(因为next[3] = 1),这相当于将子串模式向右滑动。由于 p6!=p1,而且 next[1] =0,所以next[7]=1,而因为 p1 = p7,所以 next[8] = next[7]+1 = 2

测试用例:
abaca:01121
ababaaababaa:011234223456

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值