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

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

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; }

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    23 引用 • 32 回帖 • 2 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 407 关注
  • V2EX

    V2EX 是创意工作者们的社区。这里目前汇聚了超过 400,000 名主要来自互联网行业、游戏行业和媒体行业的创意工作者。V2EX 希望能够成为创意工作者们的生活和事业的一部分。

    16 引用 • 236 回帖 • 243 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 655 关注
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    730 引用 • 1282 回帖 • 1 关注
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 38 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    86 引用 • 165 回帖
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖 • 4 关注
  • OpenShift

    红帽提供的 PaaS 云,支持多种编程语言,为开发人员提供了更为灵活的框架、存储选择。

    14 引用 • 20 回帖 • 661 关注
  • Thymeleaf

    Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。类似 Velocity、 FreeMarker 等,它也可以轻易的与 Spring 等 Web 框架进行集成作为 Web 应用的模板引擎。与其它模板引擎相比,Thymeleaf 最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个 Web 应用。

    11 引用 • 19 回帖 • 393 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • 一些有用的避坑指南。

    69 引用 • 93 回帖 • 1 关注
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 615 关注
  • V2Ray
    1 引用 • 15 回帖 • 3 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖 • 2 关注
  • PWL

    组织简介

    用爱发电 (Programming With Love) 是一个以开源精神为核心的民间开源爱好者技术组织,“用爱发电”象征开源与贡献精神,加入组织,代表你将遵守组织的“个人开源爱好者”的各项条款。申请加入:用爱发电组织邀请帖
    用爱发电组织官网:https://programmingwithlove.stackoverflow.wiki/

    用爱发电组织的核心驱动力:

    • 遵守开源守则,体现开源&贡献精神:以分享为目的,拒绝非法牟利。
    • 自我保护:使用适当的 License 保护自己的原创作品。
    • 尊重他人:不以各种理由、各种漏洞进行未经允许的抄袭、散播、洩露;以礼相待,尊重所有对社区做出贡献的开发者;通过他人的分享习得知识,要留下足迹,表示感谢。
    • 热爱编程、热爱学习:加入组织,热爱编程是首当其要的。我们欢迎热爱讨论、分享、提问的朋友,也同样欢迎默默成就的朋友。
    • 倾听:正确并恳切对待、处理问题与建议,及时修复开源项目的 Bug ,及时与反馈者沟通。不抬杠、不无视、不辱骂。
    • 平视:不诋毁、轻视、嘲讽其他开发者,主动提出建议、施以帮助,以和谐为本。只要他人肯努力,你也可能会被昔日小看的人所超越,所以请保持谦虚。
    • 乐观且活跃:你的努力决定了你的高度。不要放弃,多年后回头俯瞰,才会发现自己已经成就往日所仰望的水平。积极地将项目开源,帮助他人学习、改进,自己也会获得相应的提升、成就与成就感。
    1 引用 • 487 回帖 • 4 关注
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    198 引用 • 543 回帖
  • Elasticsearch

    Elasticsearch 是一个基于 Lucene 的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于 RESTful 接口。Elasticsearch 是用 Java 开发的,并作为 Apache 许可条款下的开放源码发布,是当前流行的企业级搜索引擎。设计用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。

    117 引用 • 99 回帖 • 197 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    79 引用 • 431 回帖
  • 微软

    微软是一家美国跨国科技公司,也是世界 PC 软件开发的先导,由比尔·盖茨与保罗·艾伦创办于 1975 年,公司总部设立在华盛顿州的雷德蒙德(Redmond,邻近西雅图)。以研发、制造、授权和提供广泛的电脑软件服务业务为主。

    8 引用 • 44 回帖 • 2 关注
  • FlowUs

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

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

    1 引用 • 4 关注
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • Follow
    4 引用 • 12 回帖 • 1 关注
  • OpenStack

    OpenStack 是一个云操作系统,通过数据中心可控制大型的计算、存储、网络等资源池。所有的管理通过前端界面管理员就可以完成,同样也可以通过 Web 接口让最终用户部署资源。

    10 引用
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 34 关注
  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 91 关注
  • AWS
    11 引用 • 28 回帖 • 8 关注