真没想到字符串匹配算法还挺难的。。。

写在前面:

最近在看王争老师的《数据结构与算法之美》,看到了字符串匹配算法,发现里面门道挺多,光是想搞明白点就花了几天功夫,鉴于我付出的精力,必须好好记录一下。

因为目前只看了单模式匹配,所以只说BF,RM,BM,KMP四个算法。

本文不会说代码实现,而是尽量理清思路,从以下几个方面入手:有什么问题?可以怎么做?为什么这么做就可以了?

先来个题目背景,在stringA中找stringB,A为主串,B为模式串,假设主串长度为n,模式串长度为m,n>m。

BF

BF暴力匹配,这个大家都清楚,最简单也是最耗时的。先一一对比,出错了就"后移1位"再从头开始对比。

这种"从头再来"的做法极大提升了算法的时间复杂度。

具体为:单次对比耗时O(m),最多进行m-n+1次对比,考虑到一般n都很大于m,所以最终复杂度简化为O(mn)。

RM

在BF算法中,主串的子串与模式串的对比时间复杂度为O(m),相当麻烦,如何快速对比两者呢?

RM算法引入了hash思想解决这一问题(hash思想:不定长的输入得到定长的输出(散列值),散列值对不上就一定不同,对上了也不一定相同,需要做额外的确认)。

先遍历一次主串,计算其子字符串的hash值,然后再和模式串的hash值对比,hash一致后再进行原值对比。

对比环节很简单,算法的关键在于计算hash环节。因为计算一个子字符串就可能需要O(m)的时间,不优化,时间复杂度就和BF差不多了。

所以该如何快速的得到随机分布的hash值呢?

这里举个例子,假设主串26572,模式串是657,假设计算hash的方法如下:

572的hash值为 510 10+710+2,其实计算572的hash时,可以利用657的计算结果,hash(572)=(hash(657)-610*10)*10+2

别看现在两者的计算量相差无几,当模式串一长,这种"递推式"的计算方式的时间复杂度为还能保持在O(1)!因此RM的时间复杂度为O(n)

BM

BM算法的核心在于两个原则:"坏字符"和"好后缀",

"坏字符"

"坏字符",顾名思义,便是比对不一致的字符。

BF算法遇到这个问题只能"滑动一步",但其实,根据模式串提供的信息,我们可以移动很多步(这里需要补充一点,无论是BM,还是KMP算法,其核心要义都是找到能"多滑动几位"的规则,这样便能快速的排除错误,排除的越多,离终点越近)。

如果在模式串找到该字符(如果有多个,取最右侧的那个),滑动2格消除"坏字符"。

为什么可以滑动2格呢?因为a在d前2格,只滑动一格,"坏字符"依旧存在

这里提一句,虽然在图中是模式串往后滑了,其实更恰当的理解是:模式串不动,主串往前滑使得"对比项"后移("对比项"aca往后移2位,变成了abd),这样更能体现"排除错误"的思想。

如果找不到,那可以移动更多位数

前文中提到了"选最右侧字符",这是为了防止错漏正确答案,可因为选最右侧字符的关系,所以可能会产生倒退,如下图。

因此如果我们一般不单独使用"坏字符"规则。

"好后缀"

在上图中,bc 便是"好后缀"(其本质是:已核对的子字符串),好后缀有什么作用呢?

如果有正确答案,答案必然包含"好后缀",不包含"好后缀"的必然不是答案,因此我们可以通过寻找"好后缀"的左侧找"一致项"来排除错误选项,"一致项"可以与"好后缀"部分重复,但不能"完全重复"

如图,我们通过"好后缀"规则滑动了3位。

为什么要滑动3位?模式串中的"一致项"在"好后缀前三位",因此"对比项"后移了三位,使得bc对上了"一致项"

找不到"好后缀"时,可能会产生问题"过度滑动"

因此,"好后缀"还有第二规则,好后缀的子后缀如果在模式串中存在且为前缀,也可以进行滑动。

为什么必须是前缀呢?因为如果不是前缀,"一致项"就必须是完整的,但现在找不到完整的,只有前缀允许不完整,实际上就是想法设法利用了部分"好后缀"

两个规则的配合

上文提到了单独使用"坏字符"会产生"倒退"现象,好在我们有两个规则:"坏字符"和"好后缀,将两个规则取到的滑动值中取大值,便实现了这个算法。

KMP

待补充。。。

相关推荐
你撅嘴真丑4 小时前
第九章-数字三角形
算法
uesowys5 小时前
Apache Spark算法开发指导-One-vs-Rest classifier
人工智能·算法·spark
ValhallaCoder5 小时前
hot100-二叉树I
数据结构·python·算法·二叉树
董董灿是个攻城狮5 小时前
AI 视觉连载1:像素
算法
智驱力人工智能5 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
孞㐑¥6 小时前
算法——BFS
开发语言·c++·经验分享·笔记·算法
月挽清风6 小时前
代码随想录第十五天
数据结构·算法·leetcode
XX風6 小时前
8.1 PFH&&FPFH
图像处理·算法
NEXT067 小时前
前端算法:从 O(n²) 到 O(n),列表转树的极致优化
前端·数据结构·算法
代码游侠7 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法