kmp算法实现思路及其代码演示

一、什么是kmp算法?

去百度上搜素一下,你会得到下面一段话:

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。

乍一看,是不是有点懵逼?什么next函数、什么局部匹配,我没看懂啊! 没关系,看了我的这篇博文,一定帮你把kmp算法安排的明明白白。

二、实例介绍

很多人想学kmp算法,可能是因为遇到字符串匹配问题:

有一个字符串str1 = “bbc abcdab abcdabcdabde” 和 一个字串 str2 = “abcdabd”
现在判断str1是否包含str2,如果存在,就返回第一次出现的位置,如果没有,就返回-1.

遇到这种问题,如果之前没学过kmp算法,肯定第一反应:暴力匹配法。就是一个个字符进行对比,直到每一个字符相同为之。但是,你也应该能意识到,这样会特别的耗时,而且程序会非常的不简洁。

那我们就先通过实现暴力匹配法,引出我们的kmp算法。

三、暴力匹配法的实现思路及其代码演示

实现思路:

  1. 假设我们给定现在str1 匹配到 i 位置,str2 匹配到 j 位置。如果当前字符匹配成功(str[i] = str[j]) ,则i++、j++,继续匹配下一个字符。
  2. 如果匹配失败。(str[i] != str[j]) 令 i = i -(j-1),j = 0; 就相当于匹配失败以后,i回溯,j重新被赋值为0.
    注:暴力匹配法可能思路上唯一难点就是这个了。
  3. 整体的思路就是这样,可以看出。每当我们匹配不成功以后,就会重新回溯一遍,相当的耗时耗力。

代码演示:

在这里插入图片描述
每一步都有详细的注释,应该挺容易理解的。
介绍完暴力匹配法,下面我们就来讲讲kmp算法。

四、kmp算法的实现思路

依然用上面那个例子

1.首先str1的第一位与str2的第一位进行比较,如果不合适,则往后移一位:
在这里插入图片描述
2.重复第一步,不合适,继续往后移:
在这里插入图片描述
3.直到str1的第一个字符与str2的第一个字符相匹配:
在这里插入图片描述
4.接着比较,还是符合:
在这里插入图片描述
5.直至匹配到两个位置字符不相符为止:
在这里插入图片描述

6.如果按照我们之前暴力匹配法的方式,肯定是将str1后移一位,然后与str2重新进行比较。这样是非常不明智的,因为BCD之前已经比较过了。当空格与D不匹配时,你已经知道前面六个字符是ABCDABD。kmp算法的思路是,设法通过这种已知的信息,不要把“搜索位置”移回到已经比较过的位置,继续把他往后移,这样就提高了效率。

我的理解是这样的,比如:你的一个子字符串是“A”开头,那么当你第一次匹配不成功时,往后移,移到下一个”A“开始,进行下一次匹配。那么你怎么知道到底移动几位,到达下一个A的位置呢?这是就要引入一个公式

移动位数 = 以匹配字符数 - 对应的部分匹配值

什么是部分匹配值

在这里插入图片描述
这就涉及到前缀与后缀的问题。

什么叫前缀与后缀?

比如说:有一个字符串 ABCDE
那么他的前缀就是去掉E 得到 A、AB、ABC、ABCD

后缀就是去掉A 得到 BCDE、CDE、DE、E

当前后缀有一个相等时,共有元素的长度如果为 1 那么部分匹配值就是 1 …

所以我们很容易的知晓:

A 没有前缀与后缀 所以他的部分匹配值是 0
AB 他的前缀是 A 后缀是 B 所以部分匹配值是 0
ABC 他的前缀是 A AB 后缀是 BC C 所以部分匹配值也是 0
ABCD 他的前缀是 A AB ABC 后缀是 BCD CD D 所以部分匹配值也是 0
ABCDA 他的前缀是 A AB ABC ABCD 后缀是 BCDA CDA DA A 有一个相同,其长度为1,所以部分匹配值是 1
ABCDAB 他的前缀是 A AB ABC ABCD ABCDA 后缀是 BCDAB CDAB DAB AB B 有1个相同,其长度为2,所一部分匹配值是 2
ABCDABD 他的前缀是 A AB ABC ABCD ABCDA ABCDAB 后缀是 BCDABD CDABD DABD ABD BD D 所以部分匹配值为 0

得到一个字串的部分匹配值以后

我们将以匹配的位数(如题目所示,六位相同,所以为6)减去 对应的部分匹配值(即最后一位匹配数,题目上是D 对应的是 2 )

这样后移4位 进行下一次比较~

口说无凭,上代码~

五、kmp算法的代码演示

在这里插入图片描述
代码还是比较简单的,主要的难点,在我看来就是kmp算法核心 那一块的代码,我也进行了注释

从代码中,我们不难看出,用kmp算法解决这些问题,大大减少了代码的时间复杂度,使代码运行的效率更高。真的很不错~

大家多多理解,一起加油呀~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值