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

写在前面:

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

因为目前只看了单模式匹配,所以只说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

待补充。。。

相关推荐
王中阳Go5 小时前
从超市收银到航空调度:贪心算法如何破解生活中的最优决策谜题?
java·后端·算法
故事挺秃然6 小时前
中文分词:机械分词算法详解与实践总结
算法·nlp
车队老哥记录生活8 小时前
【MPC】模型预测控制笔记 (3):无约束输出反馈MPC
笔记·算法
地平线开发者8 小时前
BEV 感知算法评价指标简介
算法·自动驾驶
不过四级不改名6779 小时前
用c语言实现简易c语言扫雷游戏
c语言·算法·游戏
C++ 老炮儿的技术栈10 小时前
手动实现strcpy
c语言·开发语言·c++·算法·visual studio
倔强的石头_11 小时前
【数据结构与算法】利用堆结构高效解决TopK问题
后端·算法
倔强的石头_11 小时前
【数据结构与算法】详解二叉树下:实践篇————通过链式结构深入理解并实现二叉树
后端·算法
哎写bug的程序员11 小时前
leetcode复盘(1)
算法·leetcode·职场和发展
风靡晚11 小时前
用于汽车毫米波雷达的四维高分辨率点云图像
人工智能·算法·机器学习·计算机视觉·汽车·信息与通信·信号处理