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

写在前面:

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

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

待补充。。。

相关推荐
东方芷兰18 分钟前
Leetcode 刷题记录 21 —— 技巧
java·算法·leetcode·职场和发展·github·idea
kyle~24 分钟前
排序---选择排序(Selection Sort)
java·算法·排序算法
编码浪子3 小时前
趣味学RUST基础篇(智能指针_结束)
开发语言·算法·rust
爱编程的化学家4 小时前
代码随想录算法训练营第六天 - 哈希表2 || 454.四数相加II / 383.赎金信 / 15.三数之和 / 18.四数之和
数据结构·c++·算法·leetcode·双指针·哈希
闲人编程7 小时前
图像去雾算法:从物理模型到深度学习实现
图像处理·人工智能·python·深度学习·算法·计算机视觉·去雾
咔咔学姐kk7 小时前
大模型微调技术宝典:Transformer架构,从小白到专家
人工智能·深度学习·学习·算法·transformer
haogexiaole8 小时前
Dijkstra 算法
算法
papership9 小时前
【入门级-算法-6、排序算法: 插入排序】
数据结构·算法·排序算法
HAH-HAH10 小时前
【蓝桥杯 2024 国 Java A】粉刷匠小蓝
c++·学习·数学·算法·职场和发展·蓝桥杯·组合数学
hweiyu0011 小时前
C++设计模式,高级开发,算法原理实战,系统设计与实战(视频教程)
c++·算法·设计模式