字符串匹配算法之 BF 算法和 RK 算法

本贴最后更新于 1950 天前,其中的信息可能已经时移俗易

BF 算法

BF 是 Brute Force 的缩写,叫做暴力匹配算法,由名字就能看得出来,真的很暴力 😃,暴力的一般都是头脑简单四肢发达,时间复杂度比较高的那种。那我们就来看看究竟有多暴力吧!
在字符串匹配中有两个概念,煮串,不对,是主串和模式串,比如说有两个字符串 A、B,需求是要在字符串 A 中查找字符串 B,那么 A 就是主串,B 就是模式串。

BF 算法的脑回路是,主串和模式串从头部字符开始匹配,如果发现有匹配的,那模式串就向右移动一位,继续按照前面的规则匹配,至到能匹配到,匹配过程大致和下面类似:

image.png

是不是很暴力啊,想都不用想,实现方式里一定有两个循环,时间复杂度想都不用想,应该挺高的吧,那我们来分析一下。假设主串和模式串的长度分别是 n 和 m,根据上面的匹配过程我们可以分析出整个过程需要匹配 n-m+1 次,每次要进行 m 次的比对,那总共就需要(n-m+1) * m 比对,时间复杂度是 O(n*m)的,这要是字符串长度比较大的话,那就挂了哇。但是,在时间软件开发中确实比较常用的呢,难道是我们都傻了么,明明那么慢的算法,还用。有天有个大牛告诉我,现实不是这样的,而是这样的,

  • 实际的软件开发中,大部分情况下,模式串和主串的长度都不会太长。而且每次模式串与主串中的子串匹配的时候,当中途遇到不能匹配的字符的时候,就可以就停止了,不需要把 m 个字符都比对一下。所以,尽管理论上的最坏情况时间复杂度是 O(n*m),但是,统计意义上,大部分情况下,算法执行效率要比这个高很多
  • 就是因为简单呀,当然是在满足性能要求条件下的话,简单就是最好的。

简单实现一下就是下面的喽:

public static int bF(String mainStr, String matStr) { int n = mainStr.length(), m = matStr.length(), k; if (m > n) { return -1; } char[] mainChars = mainStr.toCharArray(); char[] matChars = matStr.toCharArray(); // 外层循环控制向右滑动次数,i记录滑动位置 for (int i = 0; i <= n - m; i++) { // k记录在一次比较过程中相等字符的个数 k = 0; for (int j = 0; j < m; j++) { if (mainChars[i + j] == matChars[j]) { k++; } else { // 在一次比较过程中,如果有不相等的字符,就结束后次轮的比较,滑动进行下一轮的比较 break; } } // 判断再一次比较完结束后,相等字符的个数是否和模式串的个数相等,如果相等就说明匹配到了, // 如果不相等,就向右滑动,进行下一轮比较 if (k == m) { return i; } } return -1; }

RK 算法

全称叫 Rabin-Karp 算,两个人名字的结合,诞生的。。
在 BF 算法中,其实就是取主串的 n-m+1 个子串和模式串进行一一比对,主要消耗就集中在子串和模式串挨个字符的比较,如果每个字符都计算一个固定的值,再和模式串使用同种方式计算的值进行比较,那就很快乐了。
RK 算法的核心思路: 通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了。
来看一下 java.utils.String 中计算 hash 值是如何做的,

public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }

它要遍历每个字符来计算 hash 值,虽然通过计算 hash 值提高了比较效率,但是计算 hash 值的代价也挺高呀,看起来效率也没提升呀,不急呀,这里就要设计其他的 hash 函数了。
要处理的字符串就只包含 a~z 这 26 个小写字母,那就用二十六进制来表示一个字符串。把 a~z 这 26 个字符映射到 0~25 这 26 个数字,a 就表示 0,b 就表示 1,以此类推,z 表示 25。来看一下十进制和二十六进制计算值的方式

image.png

那一个 m 长度的 adf...gaf 字符串的 hash 值就是

image.png

只要事先计算好这些 26^(m-1)的值,那就可以大幅度提高效率。

public static int rK(String mainStr, String matStr) { int m = mainStr.length(), n = matStr.length(), s, j; int[] hash = new int[m - n + 1]; int[] table = new int[26]; char[] a1 = mainStr.toCharArray(); char[] b1 = matStr.toCharArray(); s = 1; //将26的次方存储在一个表里,取的时候直接用 for (j = 0; j < 26; j++) { table[j] = s; s *= 26; } for (int i = 0; i <= m - n; i++) { s = 0; for (j = 0; j < n; j++) { s += (a1[i + j] - 'a') * table[n - 1 - j]; } hash[i] = s; } s = 0; for (j = 0; j < n; j++) { s += (b1[j] - 'a') * table[n - 1 - j]; } for (j = 0; j < m - n + 1; j++) { if (hash[j] == s) { return j; } } return -1; }

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    66 引用 • 114 回帖 • 194 关注
  • 支付宝

    支付宝是全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验,及转账收款/水电煤缴费/信用卡还款/AA 收款等生活服务应用。

    29 引用 • 347 回帖
  • Rust

    Rust 是一门赋予每个人构建可靠且高效软件能力的语言。Rust 由 Mozilla 开发,最早发布于 2014 年 9 月。

    58 引用 • 22 回帖 • 5 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 317 关注
  • 倾城之链
    23 引用 • 66 回帖 • 168 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    192 引用 • 291 回帖 • 373 关注
  • 反馈

    Communication channel for makers and users.

    121 引用 • 907 回帖 • 273 关注
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    693 引用 • 537 回帖 • 1 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 58 关注
  • AngularJS

    AngularJS 诞生于 2009 年,由 Misko Hevery 等人创建,后为 Google 所收购。是一款优秀的前端 JS 框架,已经被用于 Google 的多款产品当中。AngularJS 有着诸多特性,最为核心的是:MVC、模块化、自动化双向数据绑定、语义化标签、依赖注入等。2.0 版本后已经改名为 Angular。

    12 引用 • 50 回帖 • 511 关注
  • H2

    H2 是一个开源的嵌入式数据库引擎,采用 Java 语言编写,不受平台的限制,同时 H2 提供了一个十分方便的 web 控制台用于操作和管理数据库内容。H2 还提供兼容模式,可以兼容一些主流的数据库,因此采用 H2 作为开发期的数据库非常方便。

    11 引用 • 54 回帖 • 667 关注
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    246 引用 • 1338 回帖
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    54 引用 • 37 回帖
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    29 引用 • 230 回帖 • 128 关注
  • TensorFlow

    TensorFlow 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。

    20 引用 • 19 回帖 • 5 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    143 引用 • 442 回帖 • 1 关注
  • Markdown

    Markdown 是一种轻量级标记语言,用户可使用纯文本编辑器来排版文档,最终通过 Markdown 引擎将文档转换为所需格式(比如 HTML、PDF 等)。

    170 引用 • 1529 回帖
  • 安全

    安全永远都不是一个小问题。

    203 引用 • 818 回帖 • 1 关注
  • GAE

    Google App Engine(GAE)是 Google 管理的数据中心中用于 WEB 应用程序的开发和托管的平台。2008 年 4 月 发布第一个测试版本。目前支持 Python、Java 和 Go 开发部署。全球已有数十万的开发者在其上开发了众多的应用。

    14 引用 • 42 回帖 • 812 关注
  • PostgreSQL

    PostgreSQL 是一款功能强大的企业级数据库系统,在 BSD 开源许可证下发布。

    22 引用 • 22 回帖 • 2 关注
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 30 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 504 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1441 引用 • 10069 回帖 • 495 关注
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 91 关注
  • 叶归
    8 引用 • 36 回帖 • 17 关注
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用