上一篇文章,我介绍了 字符串匹配的KMP算法

但是,它并不是效率最高的算法,实际采用并不多。各种文本编辑器的” 查找” 功能(Ctrl+F),大多采用 Boyer-Moore 算法。

下面,我根据 Moore 教授自己的例子来解释这种算法。

1.

假定字符串为”HERE IS A SIMPLE EXAMPLE”,搜索词为”EXAMPLE”。

2.

首先,” 字符串” 与” 搜索词” 头部对齐,从尾部开始比较。

这是一个很聪明的想法,因为如果尾部字符不匹配,那么只要一次比较,就可以知道前 7 个字符肯定不是要找的结果。

我们看到,”S” 与”E” 不匹配。这时,“S” 就被称为” 坏字符”(bad character),即不匹配的字符。我们还发现,”S” 不包含在搜索词”EXAMPLE” 之中,这意味着可以把搜索词直接移到”S” 的后一位。

3.

依然从尾部开始比较,发现”P” 与”E” 不匹配,所以”P” 是” 坏字符”。但是,”P” 包含在搜索词”EXAMPLE” 之中。所以,将搜索词后移两位,两个”P” 对齐。

4.

我们由此总结出 “坏字符规则”:

后移位数 = 坏字符的位置 – 搜索词中的上一次出现位置

如果” 坏字符” 不包含在搜索词之中,则上一次出现位置为 -1。

以”P” 为例,它作为” 坏字符”,出现在搜索词的第 6 位(从 0 开始编号),在搜索词中的上一次出现位置为 4,所以后移 6 – 4 = 2 位。再以前面第二步的”S” 为例,它出现在第 6 位,上一次出现位置是 -1(即未出现),则整个搜索词后移 6 – (-1) = 7 位。

5.

依然从尾部开始比较,”E” 与”E” 匹配。

6.

比较前面一位,”LE” 与”LE” 匹配。

7.

比较前面一位,”PLE” 与”PLE” 匹配。

8.

比较前面一位,”MPLE” 与”MPLE” 匹配。我们把这种情况称为” 好后缀”(good suffix),即所有尾部匹配的字符串。注意,”MPLE”、”PLE”、”LE”、”E” 都是好后缀。

9.

比较前一位,发现”I” 与”A” 不匹配。所以,”I” 是” 坏字符”。

10.

根据” 坏字符规则”,此时搜索词应该后移 2 – (-1)= 3 位。问题是,此时有没有更好的移法?

11.

我们知道,此时存在”好后缀”。所以,可以采用 “好后缀规则”:

后移位数 = 好后缀的位置 – 搜索词中的上一次出现位置

计算时,位置的取值以” 好后缀” 的最后一个字符为准。如果” 好后缀” 在搜索词中没有重复出现,则它的上一次出现位置为 -1。

所有的” 好后缀”(MPLE、PLE、LE、E)之中,只有”E” 在”EXAMPLE” 之中出现两次,所以后移 6 – 0 = 6 位。

12.

可以看到,” 坏字符规则” 只能移 3 位,” 好后缀规则” 可以移 6 位。所以,Boyer-Moore 算法的基本思想是,每次后移这两个规则之中的较大值。

更巧妙的是,这两个规则的移动位数,只与搜索词有关,与原字符串无关。因此,可以预先计算生成《坏字符规则表》和《好后缀规则表》。使用时,只要查表比较一下就可以了。

13.

继续从尾部开始比较,”P” 与”E” 不匹配,因此”P” 是” 坏字符”。根据” 坏字符规则”,后移 6 – 4 = 2 位。

14.

从尾部开始逐位比较,发现全部匹配,于是搜索结束。如果还要继续查找(即找出全部匹配),则根据” 好后缀规则”,后移 6 – 0 = 6 位,即头部的”E” 移到尾部的”E” 的位置。

字符串匹配的 Boyer-Moore 算法的更多相关文章

  1. [小专题]另一种字符串匹配的思路——Shift-And算法

    吐槽:前两天打组队赛遇到一个字符串的题考了这个(见:http://acm.hdu.edu.cn/showproblem.php?pid=5972 ) 当时写了个KMP瞎搞然后TLE了(害),赛后去查了 ...

  2. 模式字符串匹配问题(KMP算法)

    这两天又看了一遍<算法导论>上面的字符串匹配那一节,下面是实现的几个程序,可能有错误,仅供参考和交流. 关于详细的讲解,网上有很多,大多数算法及数据结构书中都应该有涉及,由于时间限制,在这 ...

  3. Boyer Moore算法(字符串匹配)

    上一篇文章,我介绍了KMP算法. 但是,它并不是效率最高的算法,实际采用并不多.各种文本编辑器的"查找"功能(Ctrl+F),大多采用Boyer-Moore算法. Boyer-Mo ...

  4. 字符串匹配的Boyer-Moore(BM)算法

    各种文本编辑器的"查找"功能(Ctrl+F),大多采用Boyer-Moore算法. Boyer-Moore算法不仅效率高,而且构思巧妙,容易理解.1977年,德克萨斯大学的Robe ...

  5. 神奇的字符串匹配:扩展KMP算法

    引言 一个算是冷门的算法(在竞赛上),不过其算法思想值得深究. 前置知识 kmp的算法思想,具体可以参考 → Click here trie树(字典树). 正文 问题定义:给定两个字符串 S 和 T( ...

  6. 字符串匹配常见算法(BF,RK,KMP,BM,Sunday)

    今日了解了一下字符串匹配的各种方法. 并对sundaysearch算法实现并且单元. 字符串匹配算法,是在实际工程中经常遇到的问题,也是各大公司笔试面试的常考题目.此算法通常输入为原字符串(strin ...

  7. 字符串匹配的KMP算法

    ~~~摘录 来源:阮一峰~~~ 字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串”BBC ABCDAB ABCDABCDABDE”,我想知道,里面是否包含另一个字符串”ABCDABD”? 许 ...

  8. sdut 2125串结构练习--字符串匹配【两种KMP算法】

    串结构练习——字符串匹配 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目链接:http://acm.sdut.edu.cn/sduto ...

  9. 字符串匹配--Karp-Rabin算法

    主要特征 1.使用hash函数 2.预处理阶段时间复杂度O(m),常量空间 3.查找阶段时间复杂度O(mn) 4.期望运行时间:O(n+m) 本文地址:http://www.cnblogs.com/a ...

随机推荐

  1. Win8.1/win10安装photoshop软件提示please uninstall and reinstall the product如何解决

    Photoshop CS6是一款编辑图片软件,在Win8系统中安装Photoshop CS6,提示:please uninstall and reinstall the product ,该如何解决? ...

  2. 咏南ISAPI中间件

    咏南ISAPI中间件 只支持WINDOWS服务器部署,中间件作为IIS的ISAPI插件部署. 基于WINDOWS的IIS,使用HTTP.SYS通讯,不依赖任何三方控件. 可以基于IIS HTTPS. ...

  3. Mongo 常用操作

    1.查询 [基本形式]db.col.find().pretty():pretty() 方法以格式化的方式来显示所有文档. [获取记录条数]:db.users.find().count(); [读取指定 ...

  4. 一个简单的开源PHP爬虫框架『Phpfetcher』

    这篇文章首发在吹水小镇:http://blog.reetsee.com/archives/366 要在手机或者电脑看到更好的图片或代码欢迎到博文原地址.也欢迎到博文原地址批评指正. 转载请注明: 吹水 ...

  5. CentOS7 限制SSH密码尝试次数

    编辑配置文件: vi /etc/pam.d/sshd 在文末添加内容: auth required pam_tally2.so deny= unlock_time= 代表失败5次,禁止访问600秒 保 ...

  6. caffe可重入单例机制分析

    一个函数可重入是指该函数可以被多个线程同时调用.大多数函数都不是可重如的,因为很多函数会修改静态数据结构里的内容,如果多个线程同时调用,势必破坏共享的静态结构.可以在不改变公共接口的情况下,将一个非重 ...

  7. 【OpenFOAM案例】02 自己动手

    前言:很多人说OpenFOAM很难,要啃上很多的理论书籍,什么流体力学.计算流体力学.矩阵理论.线性代数.数值计算.C++程序设计神马的,看看光这一堆书就能吓倒绝大多数的人.其实我们并不一定要从这些基 ...

  8. Python中_,__,__xx__的区别

    _xx 单下划线开头 Python中没有真正的私有属性或方法,可以在你想声明为私有的方法和属性前加上单下划线,以提示该属性和方法不应在外部调用.如果真的调用了也不会出错,但不符合规范. #! /usr ...

  9. Tomcat 配置详解/优化方案(转)

    转载地址:https://blog.csdn.net/cicada688/article/details/14451541/ Service.xml Server.xml配置文件用于对整个容器进行相关 ...

  10. Integer.parseInt vs Integer.valueOf

    一直搞不清楚这两个有什么区别.刚才特意查了一下帖子. Integer.parseInt 返回的是 primitive int Integer.valueOf  返回的是 Integer Object ...