哈希、散列表和Rabin-Karp算法

字典

现有一个抽象数据类型(ADT)如下:

包括了一组元素,每个元素都有一个键key。假设没有元素拥有相同的key,如果有相同的key,则覆盖掉原有key的元素。

-insert(item)

-delete(item)

-search(key):根据给定的key,返回元素,如果没有,则报告不存在。

假如用树形结构实现该ADT,则需要时间复杂度O(logn);而python的dictionary字典类型,可以以O(1)的时间实现。

字典的简单实现

可以用数组来简单实现字典,数组下标等于key,在对应的数组下标处存放相应的元素。

但这样有两个问题:

  1. 会占用大量的内存空间,造成存储空间的巨大浪费;
  2. 并且key的值不一定是非负数。

解决方案

对②的解决方案:prehash

  • 将key映射为非负数
  • 理论上,key是有穷数,并且是离散的。计算机中的任何东西最终都可以被表示为一连串的bit,而一连串的bit又能用一个整数表示。
  • 在python中,hash(x)相当于x的prehash。
  • prehash可能会得到相同的值。理想的情况是hash(x)==hash(y) <=> x=y

对①的解决方案:hashing

hashing方法可以将全部u个keys,减少为可接受的数量大小m。简单来说就是形成一个散列表,通过散列函数hash(x),将原来键空间内的键放入散列表中进行存放。因为散列函数本身会有冲突collision(即x ≠ y,但hash(x) = hash(y) ),所以散列表下某个键里可能有多个来自键空间内的items。而为了处理这种情况,拉链法Chaining出现了,它是将散列表每个槽内中的冲突元素进行链接。拉链法最差的情况是所有的元素都发生碰撞,所有的元素都被链接在一条链表上,时间复杂度为O(n)。

如果该散列表是简单平均式散列(即每个键被平均(uniformally)地hash到表内的槽里,并假设有n个keys和m个槽,那么散列表里链长度为n / m = α = load factor。而运行时间为Ο(1 + |chain|) = Ο(1 + α), 其中1指计算hash的时间,|chain|是指形成chain的时间等于它的长度。简单平均式散列是一种理想情况,现实中是几乎不可能存在的。

散列函数

介绍三种散列函数。

(1)Divison Method

h(k) = k mod m    (mod为求余)

(2)Multiplication Method

h(k) = [(a * k) mod 2w] >> (w - r)    (k为w bits,m=2r, ‘>>’为shift right操作)

(3)Universal Hashing

h(k) = [(a * k + b) mod p] mod m    (a和b为从{0,...,p-1}中抽取的随机数,p为大于|u|的质数,质数是只能被1和自身整除的数,u为key space的大小)

对于最差情况k1 ≠ k2下, P{h(k1) = h(k2)} = 1 / m,其小于简单平均式散列下的n / m。

hash用于字符串匹配

假设s为子串,t为主串。

简单的暴力算法伪代码如下:

for i in range (len(t) - len(s))if(s == t[i:i+len(s)])return i
return -1

时间复杂度为O(|s| * (|t| - |s|)) = O(|s|*|t|)

如何用hash来解决字符串匹配问题,使其能在线性时间复杂度内完成?

一个想法是,将比较主串与子串的每一个字符改为比较主串与子串的哈希值。但每次移动子串,都重新计算t[i:i+len(s)]中每个字符的哈希值显然不会提高效率,其时间复杂度还是O(|s|*|t|)。

如何改进?

可以想到,再后移子串的时候,前len(s)-1个字符的哈希值已经计算过,我们能否将前面已经计算过的哈希值用于下一次的哈希运算呢?如果可以的话,就只需计算新加入的字符的哈希值即可,这样便可以大幅提高时间性能。

基于这个想法,可以提出滚动哈希(Rolling Hash)的ADT:

r中维护了字符串x

- r.append(c) : 将字符c加入字符串x的末尾

- r.skip(&c) : 将字符串x的第一个字符删除,并用字符c接收删除的字符

- r.h() : 返回h(x)的值,h(x)为计算x哈希值的函数

当然,通过哈希值来匹配字符串可能会出现碰撞的情况,即h(x1) == h(x2),但x1 != x2;因此要对这种情况做特殊处理:假如h(x1) == h(x2)了,那么再逐个比较x1和x2的每个字符,如果x1==x2了,则返回i,如果x1 != x2,则继续匹配。

以上便是Rabin-Karp算法的主要思想。

伪代码如下:

for c in Srs.append(c)
for c in t[:len(s)]rt.append(c)
if rs.h() == rt.h()return 0for i in range (len(s), len(t))rt.skip(t[i-len(s)])rt.append(t[i])if rs.h() == rt.h()if s == t[i-len(s)+1 : i+1]# found matchreturn i-len(s)+1else# happens with possibility <= 1/|s|continue

时间复杂度为O(|s| + |t| + rs.h()==rt.h()的次数* |s|)

如果哈希函数设置的得当,发生碰撞的可能性是很小的,因此可将该算法的时间复杂度视为线性的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/763161.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JetBrains全家桶激活,分享 GoLand 2024 激活的方案

大家好&#xff0c;欢迎来到金榜探云手&#xff01; GoLand 公司简介 JetBrains 是一家专注于开发工具的软件公司&#xff0c;总部位于捷克。他们以提供强大的集成开发环境&#xff08;IDE&#xff09;而闻名&#xff0c;如 IntelliJ IDEA、PyCharm、和 GoLand等。这些工具被…

第4周 Python程序流程控制刷题(循环结构)

单击题目&#xff0c;直接跳转到页面刷题&#xff0c;一周后公布答案。 P5722&#xff1a;数列求和B2054&#xff1a;求平均年龄B2059&#xff1a;奇数求和B2064&#xff1a;斐波那契数列B2077&#xff1a;角谷猜想B2098&#xff1a;整数去重B2128&#xff1a;素数个数 1. P5…

力扣每日练习(3.20)补

322. 零钱兑换 想象你有一堆不同面值的硬币&#xff0c;现在的任务是用这些硬币凑出一个指定的金额&#xff0c;比如说11元&#xff0c;而且要求用的硬币数量尽可能少。 准备工作&#xff1a;首先&#xff0c;我们做了一张表&#xff08;叫dp&#xff09;&#xff0c;这张表记…

前端开发的第三方库

base64.js 地址&#xff1a;https://github.com/dankogai/js-base64 Base64.js 库提供了一个简单的 API&#xff0c;用于将数据转换为 Base64 编码&#xff0c;以及将 Base64 编码的数据解码回原始数据 Base64.js 是一个 JavaScript 库&#xff0c;用于将数据转换为 Base64 编…

LVGL:拓展部件——键盘 lv_keyboard

一、概述 此控件特点&#xff1a; 特殊Button矩阵&#xff1a;lv_keyboard 本质上是一个经过定制的按钮矩阵控件。每个按钮都可以独立触发事件或响应。预定义的键映射&#xff1a;lv_keyboard 自带了一套预设的按键布局和对应的字符映射表&#xff0c;开发者可以根据需要选择…

Vue 性能不给力?这些优化技巧帮你轻松搞定!

结合lighthouse查看各项数据&#xff0c;不断进行性能优化&#xff0c;可以从代码、项目打包、项目部署这三个层面来优化 代码层面 1、v-if和v-show区分使用 v-if&#xff08;惰性的&#xff09;用的条件判断&#xff0c;是惰性的&#xff0c;false的话初始不会渲染&#xf…

oracle迁移至gbase,sql问题总结(完善中)

最近再做国产化适配&#xff0c;需要把oracle里面的数据迁移至gbase 8a库中&#xff0c;这边把迁移过程中遇到的sql问题&#xff0c;记录下&#xff0c;现在仅迁移了一部分&#xff0c;后续会继续完善 1.ORACLE里面的NVL2函数在8a中不支持&#xff0c;可换成DECODE函数 2.表别…

二鼠打洞问题

文章目录 二鼠打洞问题测试说明Python求解 二鼠打洞问题 《九章算术》的“盈不足篇”里有一个很有意思的老鼠打洞问题。原文是这么说的&#xff1a;今有垣厚十尺&#xff0c;两鼠对穿。大鼠日一尺&#xff0c;小鼠亦一尺。大鼠日自倍&#xff0c;小鼠日自半。问&#xff1a;何…

此站点正在尝试打开 ,chrome/edge 允许http网站打开url schema

正常https链接会有首次允许选项 但http没有&#xff0c;每次都会弹出&#xff0c;非常烦人。 Chrome / Edge 配置 地址栏输入 chrome://flags/搜索Insecure origins treated as secure, 配置允许网站&#xff0c;需要协议和端口再次跳转会显示始终允许选项

关于5.x版本的Neo4j与py2neo的访问技巧

先说结果。 Neo4j是可以使用py2neo来操作的。而且网上搜到的教程和方法里&#xff0c;首推的http连接方法可能并不是最好的&#xff0c;应该用 bolt 方法可能更好。 对于大多数使用 py2neo 与 Neo4j 数据库进行交互的应用程序来说&#xff0c;建议使用 Bolt 协议&#xff08;即…

kafka面试篇

消息队列的作用&#xff1a;异步、削峰填谷、解耦 高可用&#xff0c;几乎所有相关的开源软件都支持&#xff0c;满足大多数的应用场景&#xff0c;尤其是大数据和流计算领域&#xff0c; kafka高效&#xff0c;可伸缩&#xff0c;消息持久化。支持分区、副本和容错。 对批处理…

C# 属性

C# 属性 访问器&#xff08;Accessors&#xff09; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks;namespace ConsoleApp2 {class Student{private str…

Linux 常用命令 chgrp

Linux 常用命令 chgrp 作用 用于更改文件或目录的所属用户组。只有文件的所有者或超级用户&#xff08;root&#xff09;可以使用 chgrp 命令来更改文件的所属用户组。在使用 chgrp 命令时需要谨慎操作&#xff0c;确保对文件和目录进行正确的用户组更改&#xff0c;以避免意…

linux C/C++ 捕获 SIGSEGV 段错误信号

程序运行遇到core dumped崩溃是常见现象&#xff0c;有时候&#xff0c;我们希望程序在崩溃的时候&#xff0c;先做点其他操作再崩溃&#xff0c;比如记录崩溃时刻的堆栈信息&#xff0c;或是提前释放一些硬件资源等等&#xff0c;那么就需要让程序捕获错误信号 下面是一个捕获…

第十五届蓝桥杯模拟考试III_物联网设计与开发官方代码分析

目录 前言&#xff1a;显示界面部分&#xff1a;页面切换:数值的轮回调整&#xff1a;传递数据&#xff1a; 前言&#xff1a; 这次模拟的效果很不好。85分&#xff0c;4h的限时我花了两天完成&#xff0c;这个时间是远远超出要求的&#xff0c;而且最后还只拿到56分&#xff0…

基于electron29版本桌面应用app开发例子

基于electron29版本桌面应用app开发例子 htmljsnode.js 开发模式 生成package.json文件&#xff1a; yarn init --yes 或 npm init --yes 运行打包 yarn dev yarn build # electron与electron-builder版本不兼容问题处理办法&#xff1a; 在package.json中scripts中添加 “…

解决在 yolov8 训练自己的数据集时,matplotlib 中文乱码问题【woodwhales.cn】

为了更好的阅读体验&#xff0c;建议移步至笔者的博客阅读&#xff1a;解决在 yolov8 训练自己的数据集时&#xff0c;matplotlib 中文乱码问题 在 yolov8 训练自己的数据集时&#xff0c;如果 class 字典使用了中文&#xff0c;则在训练过程中会出现形如下面的警告&#xff1a…

面试官:(...)扩展运算符是深拷贝吗?

一、情景再现 金三银四&#xff0c;最近找工作的小伙伴是扑面而来&#xff0c;这其中少不了我的好朋友张某某同学&#xff0c;我们‘相依为命’&#xff0c;我经常开导他&#xff0c;这不最近的一次面试中他就遇到这样一个考题&#xff1a; 面试官&#xff1a;&#xff08;...&…

亚远景科技-什么是Hardware SPICE(HW SPICE)硬件过程改进与能力判定模型 ?

intacs硬件SPICE&#xff08;Software Process Improvement and Capability Determination for Hardware Engineering&#xff09;是一种针对硬件工程领域的过程改进和能力评估模型&#xff0c;旨在支持电子硬件开发。它是基于SPICE&#xff08;软件过程改进和能力评估&#xf…

【NumPy数值计算基础】NumPy数组的基本操作

目录 一、数组的索引和切片&#xff08;一&#xff09;数组的索引&#xff08;二&#xff09;数组的切片 二、数组的变换&#xff08;一&#xff09;数组转置&#xff08;二&#xff09;数组重塑&#xff08;三&#xff09;数组合并&#xff08;四&#xff09;数组分割 三、数组…