漫画:如何优化 “字符串匹配算法”?

简介: BF算法是如何工作的?正如同它的全称BruteForce一样,BF算法使用简单粗暴的方式,对主串和模式串进行逐个字符的比较。

640.png

说起“字符串匹配”,恐怕算得上是计算机领域应用最多的功能之一,为了满足这一需求,聪明的计算机科学家们发明了许多巧妙的算法。

在上一篇漫画中,我们介绍了BF算法和RK算法,没看过的小伙伴可以先补补课:

漫画:什么是字符串匹配算法?

今天,我们来介绍一种性能大大优化的字符串匹配算法。

 640.jpg640.jpg640.jpg

 

 

BF算法是如何工作的?


 

正如同它的全称BruteForce一样,BF算法使用简单粗暴的方式,对主串和模式串进行逐个字符的比较。

比如给定主串和模式串如下:

 640.png

它们的比较过程是什么样的呢?


 

第一轮,模式串和主串的第一个等长子串比较,发现第0字符一致,第1位字符一致,第2位字符不一致:

 

640.png640.png640.png

 

第二轮,模式串向后挪动一位,和主串的第二个等长子串比较,发现第0位字符不一致:

 

640.png

 

第三轮,模式串继续向后挪动一位,和主串的第三个等长子串比较,发现第0位字符不一致:

640.png


以此类推,一直到第N轮:

 640.png

当模式串挪动到某个合适位置,逐个字符比较,发现每一位字符都是匹配时,比较结束:

640.png640.jpg640.jpg640.jpg640.jpg640.jpg640.jpg

 

坏字符规则


 

“坏字符” 是什么意思?就是指模式串和子串当中不匹配的字符。

还以上面的字符串为例,当模式串和主串的第一个等长子串比较时,子串的最后一个字符T就是坏字符:

 640.png640.jpg640.jpg

当检测到第一个坏字符之后,我们有必要让模式串一位一位向后挪动和比较吗?并不需要。

因为只有模式串与坏字符T对齐的位置也是字符T的情况下,两者才有匹配的可能。

不难发现,模式串的第1位字符也是T,这样一来我们就可以对模式串做一次“乾坤大挪移”,直接把模式串当中的字符T和主串的坏字符对齐,进行下一轮的比较:
640.png

 

坏字符的位置越靠右,下一轮模式串的挪动跨度就可能越长,节省的比较次数也就越多。这就是BM算法从右向左检测的好处。

 

接下来,我们继续逐个字符比较,发现右侧的GCG都是一致的,但主串当中的字符A,是又一个坏字符:

 

640.png

 

我们按照刚才的方式,找到模式串的第2位字符也是A,于是我们把模式串的字符A和主串中的坏字符对齐,进行下一轮比较:

 

640.png

 

接下来,我们继续逐个字符比较,这次发现全部字符都是匹配的,比较公正完成:

640.png640.jpg640.jpg640.png640.jpg640.jpg

//在模式串中,查找index下标之前的字符是否和坏字符匹配
private
static
int
 findCharacter
(
String
 pattern
,
char
 badCharacter
,
int
 index
)
{
for
(
int
 i
=
 index
-
1
;
 i
>=
0
;
 i
--){
if
(
pattern
.
charAt
(
i
)
==
 badCharacter
){
return
 i
;
}
}
//模式串不存在该字符,返回-1
return
-
1
;
}
public
static
int
 boyerMoore
(
String
 str
,
String
 pattern
)
{
int
 strLength 
=
 str
.
length
();
int
 patternLength 
=
 pattern
.
length
();
//模式串的起始位置
int
 start 
=
0
;
while
(
start 
<=
 strLength 
-
 patternLength
)
{
int
 i
;
//从后向前,逐个字符比较
for
(
i 
=
 patternLength 
-
1
;
 i 
>=
0
;
 i
--)
{
if
(
str
.
charAt
(
start
+
i
)
!=
 pattern
.
charAt
(
i
))
//发现坏字符,跳出比较,i记录了坏字符的位置
break
;
}
if
(
i 
<
0
)
{
//匹配成功,返回第一次匹配的下标位置
return
 start
;
}
//寻找坏字符在模式串中的对应
int
 charIndex 
=
 findCharacter
(
pattern
,
 str
.
charAt
(
start
+
i
),
 i
);
//计算坏字符产生的位移
int
 bcOffset 
=
 charIndex
>=
0
?
 i
-
charIndex 
:
 i
+
1
;
        start 
+=
 bcOffset
;
}
return
-
1
;
}
public
static
void
 main
(
String
[]
 args
)
{
String
 str 
=
"GTTATAGCTGGTAGCGGCGAA"
;
String
 pattern 
=
"GTAGCGGCG"
;
int
 index 
=
 boyerMoore
(
str
,
 pattern
);
System
.
out
.
println
(
"首次出现位置:"
+
 index
);
}

640.jpg640.jpg好后缀规则


 

“好后缀” 又是什么意思?就是指模式串和子串当中相匹配的后缀。

让我们看一组新的例子:

640.png

对于上面的例子,如何我们继续使用“坏字符规则”,会有怎样的效果呢?

从后向前比对字符,我们发现后面三个字符都是匹配的,到了第四个字符的时候,发现坏字符G

 

640.png

 

接下来我们在模式串找到了对应的字符G但是按照坏字符规则,模式串仅仅能够向后挪动一位:

640.png

 

这时候坏字符规则显然并没有起到作用,为了能真正减少比较次数,轮到我们的好后缀规则出场了。由于好后缀规则的实现细节比坏字符规则要难理解得多,所以我们这里只介绍一个大概思路:

 640.png

我们回到第一轮的比较过程,发现主串和模式串都有共同的后缀“GCG”,这就是所谓的“好后缀”。

如果模式串其他位置也包含与“GCG”相同的片段,那么我们就可以挪动模式串,让这个片段和好后缀对齐,进行下一轮的比较:

 

640.png

 

显然,在这个例子中,采用好后缀规则能够让模式串向后移动更多位,节省了更多无谓的比较。

640.jpg640.png640.jpg640.png640.jpg640.jpg640.jpg640.jpg640.jpg640.jpg


相关文章
|
4天前
|
存储 监控 NoSQL
Redis处理大量数据主要依赖于其内存存储结构、高效的数据结构和算法,以及一系列的优化策略
【5月更文挑战第15天】Redis处理大量数据依赖内存存储、高效数据结构和优化策略。选择合适的数据结构、利用批量操作减少网络开销、控制批量大小、使用Redis Cluster进行分布式存储、优化内存使用及监控调优是关键。通过这些方法,Redis能有效处理大量数据并保持高性能。
22 0
|
2天前
|
算法
MATLAB|【免费】融合正余弦和柯西变异的麻雀优化算法SCSSA-CNN-BiLSTM双向长短期记忆网络预测模型
这段内容介绍了一个使用改进的麻雀搜索算法优化CNN-BiLSTM模型进行多输入单输出预测的程序。程序通过融合正余弦和柯西变异提升算法性能,主要优化学习率、正则化参数及BiLSTM的隐层神经元数量。它利用一段简单的风速数据进行演示,对比了改进算法与粒子群、灰狼算法的优化效果。代码包括数据导入、预处理和模型构建部分,并展示了优化前后的效果。建议使用高版本MATLAB运行。
|
4天前
|
算法 搜索推荐 程序员
第六十五练 字符串匹配 - Rabin-Karp算法
第六十五练 字符串匹配 - Rabin-Karp算法
6 1
|
4天前
|
算法 搜索推荐 程序员
第六十四练 字符串匹配 - Boyer-Moore算法
第六十四练 字符串匹配 - Boyer-Moore算法
8 0
|
4天前
|
算法 搜索推荐 程序员
第六十三练 字符串匹配 - KMP算法
第六十三练 字符串匹配 - KMP算法
7 2
|
4天前
|
算法 C语言 人工智能
|
4天前
|
资源调度 算法 块存储
m基于遗传优化的LDPC码OMS译码算法最优偏移参数计算和误码率matlab仿真
MATLAB2022a仿真实现了遗传优化的LDPC码OSD译码算法,通过自动搜索最佳偏移参数ΔΔ以提升纠错性能。该算法结合了低密度奇偶校验码和有序统计译码理论,利用遗传算法进行全局优化,避免手动调整,提高译码效率。核心程序包括编码、调制、AWGN信道模拟及软输入软输出译码等步骤,通过仿真曲线展示了不同SNR下的误码率性能。
9 1
|
4天前
|
算法 Serverless
m基于遗传优化的LDPC码NMS译码算法最优归一化参数计算和误码率matlab仿真
MATLAB 2022a仿真实现了遗传优化的归一化最小和(NMS)译码算法,应用于低密度奇偶校验(LDPC)码。结果显示了遗传优化的迭代过程和误码率对比。遗传算法通过选择、交叉和变异操作寻找最佳归一化因子,以提升NMS译码性能。核心程序包括迭代优化、目标函数计算及性能绘图。最终,展示了SNR与误码率的关系,并保存了关键数据。
17 1
|
4天前
|
算法 调度
考虑需求响应的微网优化调度模型【粒子群算法】【matlab】
考虑需求响应的微网优化调度模型【粒子群算法】【matlab】
|
4天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。