kmp算法动图详解-上

kmp算法详解-上

算法简介

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

kmp算法的核心就是利用匹配串的前缀表来做失败后匹配串的回溯,从而保证主串不回溯。减少匹配次数。

关于前缀表

  • 前缀:以第一个字符开头、不包含最后一个字符的所有连续子串均称为前缀;
  • 后缀:以最后一个字符结尾、不包含第一个字符的所有连续子串均称为后缀;
  • 最长相等(公共)前后缀:前缀子串 = 后缀子串 且 长度最长;
  • 前缀表:记录下标i之前(包括i)的字符串的最长相等前后缀的长度。

有点干巴,举个例子。

abacab这个字符串对应的前缀表为:

下标012345
字符串aababaabacabacaabacab
最长相等前后缀aaab
最长相等前后缀长度001012

前缀表的使用

前缀表是用来回溯匹配串用的,下面我们看一个例子:

  • 主串: ababahop
  • 匹配串:abah

首先我们求一下匹配串的前缀表

下标0123
字符串aababaabah
最长相等前后缀a
最长相等前后缀长度0010

使用i遍历主串,使用j遍历匹配串,

1、如果ij指示的字符相等则ij均后移。

在这里插入图片描述

2、当移动到下标3的时候,主串和匹配串字符不相等,则i不动,j回溯到next[2]的位置,也就是我们前面求得的前缀表下标位2的值,此时j等于1,重复步骤一。

在这里插入图片描述

3、j移动到字符串末尾,说明找到了匹配串在主串中的位置。

为什么是前缀表

很多博主讲到这里就开始讲如何计算前缀表了,你是否有想过为什么匹配串一定要回溯到next[j-1]的位置呢,回溯到其他位置不行吗?理论依据是什么?

1、假设主串和匹配串下标移动到某一个位置,出现字符不相等。此时按照kmp算法匹配串下标j需要回溯,我们我们把主串叫做haystack,匹配串叫做pattern,此时haystack[0~i] = pattern[0~j],即蓝色部分。

在这里插入图片描述

2、假设匹配串j回溯到某一位置,使得匹配串和主串重新匹配,长度为m,即橙黄色部分。

在这里插入图片描述

3、由于我们知道蓝色部分是相等的,所以我们将他们平移对齐,做一个比较,会发现,此时haystack[0~m] = haystack[i-m~i]也可以说成是pattern[0~m] = pattern[i-m~i],即前缀等于后缀。由此可知匹配失败后匹配串下标回溯位置就是当前字符前面子串的前缀和后缀相等的位置m,即next[j-1]。

在这里插入图片描述

结束语

下一章我们讲一下如何计算前缀表,以及kmp算法如何进行优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安静的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值