算法之字符串匹配一

2023-11-11

目录

前言:

BF算法:

RK算法 

总结:

参考资料


前言:

字符串匹配指的是一个短点的字符串与一个长点的字符串进行匹配,并确认短的字符串是否在长的字符串中存在。匹配算法有很多,本文介绍两种简单、容易理解的两种算法、BF算法和RK算法。


BF算法:

BF是brute Force缩写,就是暴力匹配算法,一种简单、好懂的算法,相应的性能不太高。

在讲解算法前,需要明白两个概念,主串和模式串。

比如说,我们在字符串A中查找字符串B,那字符串A是主串,字符串B是模式串。我们把主串的长度记做n,模式串的长度记为m。n>m。

BF算法的核心思想用一句话来描述为:我们在主串中,检查起始位置分别是 0、1、2....n-m 且长度为 m 的 n-m+1 个子串,看有没有跟模式串匹配的。

 在极端情况下,比如主串是“aaaaa....aaaaaa”(省略号表示有很多重复的字符 a),模式串是“aaaaab”。我们每次都比对 m 个字符,要比对 n-m+1 次,所以,这种算法的最坏情况时间复杂度是 O(n*m)。

尽管BF算法的时间复杂度很高,但是它却是一个比较常用的字符串匹配算法,

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

第二,朴素字符串匹配算法思想简单,代码实现也非常简单。简单意味着不容易出错,如果有 bug 也容易暴露和修复。在工程中,在满足性能要求的前提下,简单是首选。这也是我们常说的KISS(Keep it Simple and Stupid)设计原则。

RK算法 

我在讲 BF 算法的时候讲过,如果模式串长度为 m,主串长度为 n,那在主串中,就会有 n-m+1 个长度为 m 的子串,我们只需要暴力地对比这 n-m+1 个子串与模式串,就可以找出主串与模式串匹配的子串。

但是,每次检查主串与子串是否匹配,需要依次比对每个字符,所以 BF 算法的时间复杂度就比较高,是 O(n*m)。我们对朴素的字符串匹配算法稍加改造,引入哈希算法,时间复杂度立刻就会降低。

RK 算法的思路是这样的:我们通过哈希算法对主串中的 n-m+1 个子串分别求哈希值,然后逐个与模式串的哈希值比较大小。如果某个子串的哈希值与模式串相等,那就说明对应的子串和模式串匹配了(这里先不考虑哈希冲突的问题,后面我们会讲到)。因为哈希值是一个数字,数字之间比较是否相等是非常快速的,所以模式串和子串比较的效率就提高了。

 

 不过,通过哈希算法计算子串的哈希值的时候,我们需要遍历子串中的每个字符。尽管模式串与子串比较的效率提高了,但是,算法整体的效率并没有提高。有没有方法可以提高哈希算法计算子串哈希值的效率呢?

这就需要哈希算法设计的非常有技巧了。我们假设要匹配的字符串的字符集中只包含 K 个字符,我们可以用一个 K 进制数来表示一个子串,这个 K 进制数转化成十进制数,作为子串的哈希值。表述起来有点抽象,

我举了一个例子,看完你应该就能懂了。比如要处理的字符串只包含 a~z 这 26 个小写字母,那我们就用二十六进制来表示一个字符串。我们把 a~z 这 26 个字符映射到 0~25 这 26 个数字,a 就表示 0,b 就表示 1,以此类推,z 表示 25。在十进制的表示法中,一个数字的值是通过下面的方式计算出来的。对应到二十六进制,一个包含 a 到 z 这 26 个字符的字符串,计算哈希的时候,我们只需要把进位从 10 改成 26 就可以。

 

整个 RK 算法包含两部分,计算子串哈希值和模式串哈希值与子串哈希值之间的比较。第一部分,我们前面也分析了,可以通过设计特殊的哈希算法,只需要扫描一遍主串就能计算出所有子串的哈希值了,所以这部分的时间复杂度是 O(n)。

模式串哈希值与每个子串哈希值之间的比较的时间复杂度是 O(1),总共需要比较 n-m+1 个子串的哈希值,所以,这部分的时间复杂度也是 O(n)。所以,RK 算法整体的时间复杂度就是 O(n)。


总结:

BF 算法是最简单、粗暴的字符串匹配算法,它的实现思路是,拿模式串与主串中是所有子串匹配,看是否有能匹配的子串。所以,时间复杂度也比较高,是 O(n*m),n、m 表示主串和模式串的长度。不过,在实际的软件开发中,因为这种算法实现简单,对于处理小规模的字符串匹配很好用。

RK 算法是借助哈希算法对 BF 算法进行改造,即对每个子串分别求哈希值,然后拿子串的哈希值与模式串的哈希值比较,减少了比较的时间。所以,理想情况下,RK 算法的时间复杂度是 O(n),跟 BF 算法相比,效率提高了很多。不过这样的效率取决于哈希算法的设计方法,如果存在冲突的情况下,时间复杂度可能会退化。极端情况下,哈希算法大量冲突,时间复杂度就退化为 O(n*m)。

参考资料

本章内容来源于对王争大佬的《数据结构与算法之美》的专栏。 

32 | 字符串匹配基础(上):如何借助哈希算法实现高效字符串匹配?-极客时间

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

算法之字符串匹配一 的相关文章

随机推荐

  • 用python画一束满天星花朵,python满天星绘制流程图

    大家好 小编来为大家解答以下问题 用python画一束满天星花朵 python满天星绘制流程图 今天让我们一起来看看吧 1 用python画一百个同心圆的代码 import matplotlib pyplot as plt from mat
  • u盘文件删除如何恢复呢?

    相信很多上班族都有自己的u盘 u盘是用来储存一些我们可以随身携带的数据的 无论是学习还是工作 只要用电脑 都需要使用u盘 而u盘就是一个小容器 可以装一些重要的文件 方便我们随身携带 当u盘里的文件在使用u盘的过程中不小心被删除了 怎么恢复
  • selenium的安装及使用介绍

    R爬虫之上市公司公告批量下载 selenium的安装及使用介绍 http yphuang github io blog 2016 03 01 Get Listed Company Announcement
  • 【超简单】使用TensorFlow训练和部署图像分类模型

    一 简介 使用TensorFlow和OpenCV实现图像分类 按照流程图运行程序 可以非常简便地完成图像预处理 生成数据集 训练模型和部署模型 四个程序的功能如下 preprocess py 对图像进行重命名和调整大小 建议拍摄形状为正方形
  • 数据流图学习

    数据流图或数据流程图 Data Flow Diagram 缩写为DFD 是什么 数据流图是结构化分析方法中使用的工具 它以图形的方式描绘数据在系统中流动和处理的过程 由于它只反映系统必须完成的逻辑功能 所以它是一种功能模型 标志了一个系统的
  • JavaScript中apply()和call()的区别和应用

    JavaScript中的每一个Function对象都有一个apply 方法和一个call 方法 这两个方法能够改变函数体内部 this 的指向 例如 fun1 call 或者fun1 apply 都是为了改变fun1函数内部的this指向
  • Java 实现 AES 对称加密算法的加解密

    Java 实现 AES 对称加密算法的加解密 前言 一 对称加密算法简介 1 对称加密 2 加密模式 3 填充模式 二 AES 加解密代码实例 1 生成 AES 密钥 2 AES 加解密 3 AES nonce 加解密 前言 文章字数比较多
  • uniapp 里折叠面板嵌套 uni-collapse 高度不能自适应解决办法

  • python:根据一个列表对另外一个列表排序

    在使用python处理数据时可能会遇到根据列表A对列表B进行排序的问题 记录一下想到的两个方法 方法1 根据列表b中每个元素的下标来获取列表a中对应位置的元素 将其作为排序依据即可 import random a x for x in ra
  • JVM你知道多少?

    1 jvm的内存结构 方法区和堆是所有线程共享的内存区域 而java栈 本地方法栈和程序计数器是运行时线程私有的内存区域 1 Java堆 Heap 是Java虚拟机所管理的内存中最大的一块 Java堆是被所有线程共享的一块内存区域 在虚拟机
  • naive bayes java_Naive Bayes 朴素贝叶斯的JAVA代码实现

    最进写毕业论文找了下贝页斯的资料 这个文章讲的很好 转载下 链接http blog csdn net michael kong nju article details 12623557 comments 1 关于贝叶斯分类 bayes 是一
  • STM32—ADC详解入门(ADC读取烟雾传感器的值)

    目录 一 ADC是什么 二 ADC的性能指标 三 ADC特性 四 ADC通道 五 ADC转换顺序 六 ADC触发方式 七 ADC转化时间 八 ADC转化模式 九 实验 使用ADC读取烟雾传感器的值 1 配置 2 代码 一 ADC是什么 AD
  • MSYS2更换国内源

    今天安装了Msys64 但是Msys64使用的国外源实在太慢 必须更新为国内源 目前测试过国内最快是清华大学的源 我的安装路径为d msys64 为什么要安装在D盘 因为msys64需要不断更新数据和安装自己的软件 也就是说会占用越来越多的
  • 使用mnist数据集实现手写字体的识别

    1 MNIST是一个入门级的计算机视觉数据集 它包含各种手写数字图片 它也包含每一张图片对应的标签 告诉我们这个是数字几 该数据集包括60000行的训练数据集 mnist train 和10000行的测试数据集 mnist test 每一张
  • mysql索引左侧原则,你真的了解吗?

    前言 写这篇文章源自一位杠精同事提了个问题 左侧原则跟where条件顺序有无关系 我想了想 好像是有关系的 不敢确定 但是自己又懒得动手测试 于是发起ETC自动抬杠功能 强行杠了一拨 结果杠输了 接下来即是动手验证 预习执行计划 实践 咱们
  • Something about C

    What the hell How long since I touch with C What a pity I have to work with it now Global variable Better define a globa
  • c++中setw()与setfill()的用法详情

    c 中setw 与setfill 的用法详情 在C 中 setw int n 用来控制输出间隔 例如 cout lt lt s lt
  • 关于自搭网站XAMPP(三)MYSQL增删改查(水)

  • Ubuntu 18.04下载安装以及分区教程

    收藏一下写的超赞的博客 Ubuntu18 04安装教程 超详细的图文教程 安装Ubuntu Linux系统时硬盘分区最合理的方法ubuntu18 04分区设置 也安装过很多次ubuntu了 记录一下最重要的踩坑点 分区完成后会让选择安装启动
  • 算法之字符串匹配一

    目录 前言 BF算法 RK算法 总结 参考资料 前言 字符串匹配指的是一个短点的字符串与一个长点的字符串进行匹配 并确认短的字符串是否在长的字符串中存在 匹配算法有很多 本文介绍两种简单 容易理解的两种算法 BF算法和RK算法 BF算法 B