Rabin-Karp算法总的来说,一句话可以概况,就是一种利用对字符串进行哈希(hash)来解决字符串匹配问题的算法。所以该算法的特点就呼之欲出了,如何对字符串进行hash呢?
  这里首先对字符串匹配问题做一个简单的概述。字符串匹配问题可以简单描述成下述形式:

  • Input:一段字符串a,和一个字符串b
    Output:如果b中含有a,那么输出True,如果没有,输出False

什么是Hash

  那么最重要的问题来了,如何对字符串进行hash呢?首先我们需要明白hash的含义,hash的含义就是通过一个函数将一个值域(初始值)映射到另一个值域(散列值),这个函数就是哈希函数,也叫散列函数。这么说有点抽象,举个栗子,对python有一定了解的都知道,python的字典就是一种hash存储模式,一般我们很难保证有一整块连续的内存来存储数据,因此会将多个数据分散存储在多个地方,但是这样不方便查找,如果我们有三个数据(key),x1,x2,x3(三个数据必须不相等,相等的数据拥有相同的hash地址),我们的hash函数是H(x) = 10*x + 5,假设我们从地址为1,2,3开始来存储这三个数据,那么我们得到的最后的地址就是15,25,35,也就是说我们通过x就可以直接得到地址,而不需要一个个去遍历查找,极大的减少了查询时间。

什么是Hash冲突

  细心的同学就发现了,如果我们的H(x)比较复杂,如果H(x) = x2 + 5,那当我们的key1 = -1, key2 = 1,他们的hash地址不就相等了么?事实上,的确是的,对于key1 != key2,但是通过H(x)算出来的hash值是一样的,这就是Hash冲突。避免hash冲突的方法有很多,比如开放地址法(再散列法)、链地址法(拉链法)、再哈希法、建立公共溢出区等等,这里就不细讲了,因为都用不着。

Rabin-Karp算法

  到这里,我们的基础知识就基本介绍完了,可以正式进入Rabin-Karp算法的介绍和实现了。我们比较两个字符串是不是匹配(相等),一般可以从头往后进行遍历,比较每一个对应位置的字符是不是相等,直到比较完所有位置或者存在对应位置字符不等。将问题提高一点,判断字符串a是不是b的子串,大家很容易想到滑动窗口,如果a的长度是m,那么滑动窗口的长度也就是m,滑动的次数是(n-m),比较的次数是m次,所以传统暴力解法的时间复杂度为(m-n)*m。
  Rabin-Karp算法其实也是基于滑动窗口来进行比较,只是它不是比较每个字符,而是比较这整个m长子串的hash值,这样无需遍历,一次比较即可完成,所有的时间复杂度是,m(构建a字符串的hash值所需要的时间复杂度) + n(遍历字符串n所需要的时间复杂度)。

对字符串进行hash

  对字符串hash也很简单,每一个字符在ASCII中均有一个独属于自己的编码比如a-z对应的编码是97-122,A-Z对应的编码是65-90。有了这些初始值,那么剩下的就是我们哈希函数的建立了。我们以26个大写字符串为例,讲解其hash函数的构建,我们发现对于长度为m的字符串,其可能组合为26m,hash函数的目的是尽可能为每一个初始值找到一个唯一的散列值,也就是说我们的hash函数的散列区间也需要满足26m,这里我们很容易就考虑到进制,即如果只有2种状态我们就考虑用2进制,10种状态就考虑用十进制,本例26种状态,我们就可以考虑用26进制来表示,举个栗子,例如我们对字符串ABCD进行哈希:

  • A-Z对应的编码是65-90,将其对应到0-25之间(表示26进制),因此A、B、C、D对应的值为0、1、2、3
    1 : H(“ABCD”) = 0*263 + 1*262 + 2*261 + 3*260= 731

  这就是字符串hash的方法,那么我们如何字符串匹配时来使用呢?难道每次的m长度窗口都要计算一次么?那时间复杂度岂不是就是O(mn)了?
  当然不是,这里用了前缀和的思想,对于"ABCDEF",其对应的编码是012345,我们滑动窗口长度为3,那么当我们计算完"ABC"的hash值了之后,我们需要计算"BCD"的hash值,由于每一个窗口的hash值实质上是一个累计和,所以我们只需要对H(“ABC”)减去A的贡献,对剩下的值乘以26,最后再加上D的贡献,就可以了,这样的时间复杂度为1。其中A的贡献为0*26m-1 (m为滑动窗口长度),C对应的贡献为 3*260
  算法原理都清楚了,接下来就是优化,即如何避免Hash冲突,首先我们要明白只要hash函数选的不是很离谱,发生冲突的概率是很低的,因此对于本题的字符串匹配问题,当hash值相等时,我们再同时比较字符串,这样时间复杂度会高一点,但是完全避免了hash冲突会引起的匹配错误。代码如下所示:

def search(a, b):"""判断a是不是b的子串>>>search( "AABA", "ACAADAABAAAAABABAA")>>>True"""hashA, hashB = 0, 0aN = [ord(c)-ord('A')+1 for c in a]bN = [ord(c)-ord('A')+1 for c in b]m, n = len(aN), len(bN)for i in range(m):hashA = 26*hashA + aN[i]hashB = 26*hashB + bN[i]for j in range(m-1, n):if j > m-1:hashB -= bN[j-m]*(26**(m-1))hashB = hashB*26 + bN[j]if hashB == hashA:if a == b[j-m+1:j+1]:return Truereturn False
search( "AABA", "ACAADAABAAAAABABAA")
  • 如果大家觉得有帮助,欢迎点个免费的赞,谢谢!

Rabin-Karp算法详解和实现(python)相关推荐

  1. Rabin Karp 算法详解及Python实现

    目录 一.Rabin Karp 核心思路 二.字符串如何做哈希映射 三.借助前缀和列表计算滑动窗口 四.leetcode28. 代码实现 Rabin Karp 算法是用于实现字符串的模式匹配,先看le ...

  2. 【机器学习】【隐马尔可夫模型-3】后向算法:算法详解+示例讲解+Python实现

    0.前排提示 csdn有些数学公式编辑不出来,所以本博用容易书写的表达式来表示专业数学公式,如: (1)  在本博客中用α<T>(i)来表示 (2)在本博客中用[i=1, N]∑来表示 注 ...

  3. python俄罗斯方块算法详解_用 Python 写一个俄罗斯方块游戏 (

    @@ -2,34 +2,34 @@ > * 原文作者:[Dr Pommes](https://medium.com/@pommes) > * 译文出自:[掘金翻译计划](https://g ...

  4. 数学建模——主成分分析算法详解Python代码

    数学建模--主成分分析算法详解Python代码 import matplotlib.pyplot as plt #加载matplotlib用于数据的可视化 from sklearn.decomposi ...

  5. AdaBoost算法详解与python实现

    AdaBoost算法详解与python实现 https://tangshusen.me/2018/11/18/adaboost/

  6. 基于多相滤波器的数字信道化算法详解(Python, Verilog代码已开源)

    基于多相滤波器的数字信道化算法详解 推导过程 总结 仿真 本文详细介绍了基于多相滤波器的数字信道化算法的推导过程, 如果您在阅读的过程中发现算法推导过程中有任何错误, 请不吝指出. 此外, 进入我的G ...

  7. RRT(Rapidly-Exploring Random Trees)算法详解及python实现

    RRT(Rapidly-Exploring Random Trees)算法详解及python实现 前言 一.原理 二.伪代码 三.代码详解 总结 前言 快速探索随机树(RRT):作为一种随机数据结构, ...

  8. 排序算法(五)——堆排序算法详解及Python实现

    本文目录 一.简介 二.算法介绍 三.代码实现 排序算法系列--相关文章 一.简介 堆排序(Heap Sort)算法,属于选择排序类,不稳定排序,时间复杂度O(nlogn). 堆排序由Floyd和Wi ...

  9. Simhash算法详解及python实现

    Simhash算法详解及python实现 GoogleMoses Charikar发表的一篇论文"detecting near-duplicates for web crawling&quo ...

  10. 【强化学习】Sarsa算法详解以及用于二维空间探索【Python实现】

    Sarsa算法 Sarsa算法,是基于Q-Learning算法.改动其实很小. 本文工作基于之前的Q-Learning的项目,如果有疑问可以看下面两个问题: [强化学习]Q-Learning算法详解以 ...

最新文章

  1. 计算机计算能力,计算机/电脑为什么拥有计算能力
  2. jvm性能调优 - 05对象在JVM内存中的分配和流转
  3. iphone ios 如何开发升级适配 iphone5 4inch
  4. oracle12154错误 Linux,关于“EXP-00056: ORACLE error 12154 encountered”的解决方法
  5. “@react-navigation/native“).createNavigatorFactory) is not a function.
  6. 开关电源环路的零极点可以在反馈端补偿吗_【干货分享】开关电源环路补偿设计步骤讲解...
  7. c语言 函数指针开销,函数指针是否使程序变慢?
  8. 制作 docker 镜像
  9. 吴恩达 深度学习 编程作业(1-3)- Planar data classification with one hidden layer(平面花形状)
  10. JUnit5 测试套件示例
  11. [BZOJ3456]城市规划
  12. xp本地服务器虚拟目录创建,WindowsXp系统怎么创建虚拟目录
  13. 数据分析数据挖掘(五)
  14. 部署速度翻6倍,知乎从0到1实现部署系统演进及优化
  15. JST日本压着端子GHD系列线对板连接器PCB封装库(1.25mm间距)
  16. android-keystool
  17. 怎么把好几行弄成一行_怎么把excel表格里多行变成一行数据|excel表格中让多行内容变成为一行...
  18. 推流拉流RMTP方案:Nginx+ffmpeg/obs+vlc/h5
  19. 2021龙岩一中高考成绩查询,喜报!龙岩这7所一中的高考成绩出炉啦~
  20. 如何挑选合适自己的内存

热门文章

  1. Windows下secureCRT、putty使用秘钥登录Linux
  2. linux测试进程内存,怎么测试进程运行时的内存用量
  3. ppt格式刷快捷键_15个PPT神操作,让老师做课件的效率翻倍!
  4. python写水仙花数
  5. 像素生存者2为什么显示服务器不可用,像素生存者2为什么更新了玩不了 | 手游网游页游攻略大全...
  6. dos下载ftp文件linux,在DOS和LINUX下的FTP命令
  7. easyui tree复选框是否打钩状态_原创深度:如何利用OpenVINO工具套件监控机器操作员情绪状态(一)...
  8. Vue:vue将按需引入element抽成单独js文件
  9. Javascript:利用JS在空白网页中绘制简单图形
  10. 面向对象(Python):学习笔记之单例模式