c++ kmp算法字符匹配_算法之KMP字符串匹配

9d28a718eb55e75b39e43d67aa986b38.png

字符匹配算法

  • BF算法

  • KMP算法


先在开头约定

文中原始待匹配字符串为text,如“ababcabc”

匹配串为pattern,如“ababc”

最长前后缀数组为prefix[ ]

11ec90ea9f7e9166986ce9fd18d32614.png

BF算法概述

BF算法属于暴力匹配算法,时间复杂度在O(mn),较为耗时间。

其原理在于从头遍历text串,当text中某字符与pattern中第一个相等时,继续将指向text的下标值(i)向后移,同时将指向pattern的下标值(j)向后移

当出现text和pattern对应字符不相等时,将i回溯至上一次开始匹配的位置的下一位,将j回溯到0的位置,重复执行此操作

当pattern被j遍历结束的时候,则表明匹配成功;当text被遍历结束的时候,则表明匹配失败,在text中未找到pattern

BF算法较为简单,这里不做详细介绍。 


ee51e14d62b79b48a91f1e048f15908e.png

KMP算法介绍

前置知识:最长公共前后缀(prefix table)

假设pattern=“ababca”,则如下图: 

4c62300cf3c109748ee2b68898778836.png

其中原始串为“ababca”,则产生六个子串。以“abab”为例,产生的不包括本身的前缀为“a”和“ab”和“aba”三个,产生的不包括本身的后缀为“b”和“ab”和“bab”三个,所以最长公共前后缀长度为2。

产生一个prefix数组,prefix[ ]={0,0,1,2,0,1},在KMP算法中,为便于算法构造,将最后一位删除,在第一位补-1,则形成prefix[ ]={-1,0,0,1,2,0}。prefix数组的作用在下文将详细给出。


算法正式开始

设text=“abaacababcac”,pattern=“ababc”。

由pattern产生的最长公共前后缀数组为prefix[ ]={-1,0,0,1,2},称为前缀表。

pattern字符串由0开始从头到尾下标为0~4,下标称作index。

遍历text的下标为i,遍历pattern的下标为j。

KMP算法比之BF算法的高明之处在于不必将i回溯,从而只需遍历一遍text,将整个算法的时间复杂度降到O(n+m)。

KMP算法的做法是将text和pattern从头进行匹配。

当匹配成功时,i和j分别向后移,直至i和j所对应的字符不一致。

这时将j往前回溯到某一特定位置,动态的想法就是将pattern串往后滑动一段距离,继续将i和j进行往后遍历,重复当前做法,直至匹配成功或者text串结束。

下面由图来讲解一下:

从头开始匹配,遇到第四位时失配:

6a519125aa951e3968fd35e36cf59459.png

这时,将P串向后滑动一段距离,而这段特定的距离就是前文prefix table的作用。

根据前缀表中,失配的P串的位置下标为3,则将P串滑动到prefix[3]的位置,也就是pattern[1]的位置。

如下图:

c4695c2b59671b25cd99e1d5cd4e2c47.png

这时,T串i指向‘a’,P串j指向‘b’,又不匹配,则继续将P串右移,如图:

bf4726f4271e6a29792740997bbd0892.png

直至!

0f63aaa218270be6c8cc5e75cd32b1d4.png

j==strlen(pattern) 时匹配成功!

这时,如果题目只要求检查是否可以匹配成功,则可以退出。

若要求求出在text中含有几个pattern串则需要继续。

将P串向右滑动特定距离。

这里的特定距离指的是P串末尾字符所对应的前缀表的位置

即P[2]的位置。

1f3707094903ca6215e2836bb74525dd.png

直至这时,整个算法结束!!!

看到这里,相信聪明的同学已经看出来prefix数组的作用了

那就是确定当失配时P串需要往后滑动的距离。

而具体怎样确定!!!

我们知道,prefix是最长公共前后缀,

例如,prefix[3]=1,即表示P[3]之前的串的最长公共前后缀长度为1,这里不包括P[3]本身。

当P串本身往后滑动后,需要寻找与前面匹配的最长距离,从而避免重复匹配损耗时间。

以第一个步骤为例:

6a519125aa951e3968fd35e36cf59459.png

当j指向b时,b之前的串最长公共前后缀的长度是1,即“aba”的最长公共前后缀长度为1。

所以P滑动到P[1]的位置,即可保证变化后的P串的j之前的1长度的串与i之前的1长度的串是完全一致的,即

f9d27fbd55484ae452a71883508a056a.png

算法介绍结束!!!

下一篇介绍具体代码实现。

才疏学浅,疏漏百出,如有错误,我也不听!

更多文章请移步brillanza.gitee.io

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法C++代码实现

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值