作者 | 小灰

来源 | 程序员小灰(ID:chengxuyuanxiaohui)

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

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

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

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

BF算法是如何工作的?

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

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

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

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

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

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

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

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

坏字符规则

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

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

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

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

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

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

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

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

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

public
static void main(String[] args) {String str = "GTTATAGCTGGTAGCGGCGAA";String pattern = "GTAGCGGCG";int index = boyerMoore(str, pattern);System.out.println("首次出现位置:" + index);
}
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;
}
//在模式串中,查找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;}}//模式串不存在该字符,返回-1return -1;
}

好后缀规则

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

让我们看一组新的例子:

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

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

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

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

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

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

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

【End】

明晚7点,直播连麦贾扬清,讲讲人工智能在近几年当中的算法和相应系统的演进过程,并从技术角度阐述产品形态和用户场景。参与公开课还有机会向贾扬清老师提问~提交听课笔记还有可能获得阿里马克杯、天猫精灵智能音箱哦~

点击阅读原文,快速报名!

推荐阅读 

☞ 抗疫新举措,本周内你也能用上健康码!

☞无人机小区上空盘一圈测体温,背后技术靠谱吗?

☞几行代码构建全功能的对象检测模型,他是如何做到的?

☞疫情之下,哪些行业正在逆势爆发?

☞早期文献中的关系抽取论文整理,赶紧 Mark 起来!

☞比特币技术栈的演进

你点的每一个在看,我认真当成了喜欢

猛戳“阅读原文”,快速报名!

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

  1. 字符串匹配算法 -- BM(Boyer-Moore) 和 KMP(Knuth-Morris-Pratt)详细设计及实现

    文章目录 1. 算法背景 2. BM(Boyer-Moore)算法 2.1 坏字符规则(bad character rule) 2.2 好后缀规则(good suffix shift) 2.3 复杂度 ...

  2. 字符串匹配算法(二):BM(BoyerMoore)算法、坏字符规则,好后缀规则

    文章目录 BM算法 坏字符规则 好后缀规则 完整代码 BM算法 BM算法的全程叫做Boyer-Moore,是工程上最常用且最高效的字符串匹配算法,有实验统计,它的性能是著名的KMP 算法的 3 到 4 ...

  3. diff算法阮一峰_【重学数据结构与算法(JS)】字符串匹配算法(三)——BM算法

    前言 文章的一开头,还是要强调下字符串匹配的思路 将模式串和主串进行比较 从前往后比较 从后往前比较 2. 匹配时,比较主串和模式串的下一个位置 3. 失配时, 在模式串中寻找一个合适的位置 如果找到 ...

  4. 大量的数据做字符串匹配_【重学数据结构与算法(JS)】字符串匹配算法(三)——BM算法...

    前言 文章的一开头,还是要强调下字符串匹配的思路 将模式串和主串进行比较 从前往后比较 从后往前比较 2. 匹配时,比较主串和模式串的下一个位置 3. 失配时, 在模式串中寻找一个合适的位置 如果找到 ...

  5. 字符串匹配算法——KMP算法学习

    KMP算法是用来解决字符串的匹配问题的,即在字符串S中寻找字符串P.形式定义:假设存在长度为n的字符数组S[0...n-1],长度为m的字符数组P[0...m-1],是否存在i,使得SiSi+1... ...

  6. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  7. iptables --algo 字符串匹配算法 bm kmp

    http://blog.csdn.net/l953972252/article/details/51331001 字符串匹配一直是计算机领域热门的研究问题之一,多种算法层出不穷.字符串匹配算法有着很强 ...

  8. 数据结构之字符串匹配算法(BF算法和KMP算法)

    字符串匹配算法: 就是给定两个串,主串(s)和子串(sub), 查找子串是否在主串里面,如果找到便返回子串在主串中第一个元素的位置下标,否贼返回-1,. 在这里我 们讨论的时候主要用字符串来举例实现. ...

  9. 一看就懂的字符串匹配算法 之 BM算法

    先来一个导读,关于BM算法开始有了难度,大家一定要静下心,咬着呀也得给我读下去,这样你才能有收获. 我们在文本编辑器中,我们经常用到查找及替换功能.比如说,在Word文件中,通过查找及替换功能,可以把 ...

最新文章

  1. 布谷鸟哈希函数的参数_用于并发读密集型的乐观Cuckoo(布谷鸟) Hashing
  2. Python3学习笔记:使用代理访问url地址
  3. 最大公约数 数学,结论 第九届“图灵杯”NEUQ-ACM程序设计竞赛个人赛
  4. Eclipse 中 按 Ctrl+Shift+F 格式化代码时每行容纳的字符数
  5. asterisk1.8 拨号方案 mysql存储(动态)
  6. .NET Mass Downloader -整体下载.NET源码
  7. php 导出excel 2007,使用PHPExcel导出Excel表
  8. php可变函数代码,PHP可变函数
  9. perl常用正则表达式集合
  10. mysql期中考试题及答案_mysql 查询 练习题及答案
  11. 吸烟首先危害是会引起火灾,电子烟较好
  12. XQuery FLWOR 表达式
  13. Vue.js身份证读卡器阅读器谷歌chrome火狐Firefox网页实现读取方法
  14. java怎么调字体_Java怎么设置字体
  15. 高德地图 Web JS API示例学习笔记(12)——Object3D 图形(通用接口、立体Mesh、线Line)
  16. thinkcmf:Cannot redeclare cmf_get_date() (previously declared in
  17. linux下光模块信息命令,华为交换机查看光模块信息命令
  18. 获取当前时间、获取当前月的第一天、获取当前年的第一天
  19. 用BitmapShader实现圆形图片
  20. 生信数据库ID大总结-想踏入生信大门的你值得拥有

热门文章

  1. javascript系列:NaN类型
  2. 《数据结构教程》(李春葆 主编)课后习题【练习题6】
  3. 程序阅读理解题目(高中语文版,附答案)
  4. ASP.NET2.0入门经典(第4版)—3.5 服务器控件的类型(2)--zt
  5. [算法] 已知前序和后序遍历,建立二叉树
  6. 本地更新github项目_【图文说明】将本地项目上传到github上
  7. 大学计算机基础上机实践报告,大学计算机基础上机实践报告书册.doc
  8. 如何让地面不起灰_地面不平能铺地板吗?木地板不平怎么修复
  9. 《推荐系统笔记(十七)》userCF和itemCF —— 基于领域的推荐
  10. SQL实战之查找所有员工的last_name和first_name以及对应部门编号dept_no