当前位置: 首页 > news >正文

字符串匹配的Rabin–Karp算法


leetcode-28 实现strStr()

更熟悉的字符串匹配算法可能是KMP算法, 但在Golang中,使用的是Rabin–Karp算法



一般中文译作 拉宾-卡普算法,由迈克尔·拉宾与理查德·卡普于1987年提出

要在一段文本中找出单个模式串的一个匹配,此算法具有线性时间的平均复杂度,其运行时间与待匹配文本和模式串的长度成线性关系。虽然平均情况下,此算法表现优异,但最坏情况下,其复杂度为文本长与模式串长的乘积

尽可能多的利用上一步的结果,这是优化时间复杂度的一大核心


对于数字类型的字符串,可有如下匹配方法:


alt

将该方法扩展到非数字类型的字符串:


alt
以上这张图片的LaTex:
$$\begin{gather}
  
对于长度为n的字符串 x_{0} x_{1} x_{2} ... x_{n-1},\\其对应的“值”val为\\

val = x_{0} \times r^{n-1} + x_{1}\times r^{n-2} + ... +  x_{n-1}\times r^{0}
 
 \\其中r为进制数\end{gather}$
alt
alt

ASCII:英语字符与二进制位之间的关系 (其他语言??)

Unicode:将世界上所有的符号都纳入其中, 每个符号都对应一个独一无二的编码,最多可以容纳1114112个字符(2021年9月公布的14.0.0,已经收录超过14万个字符) (有个问题是浪费空间。。) 也译作统一码/万国码/国际码

UTF-8: 使用最广的一种 Unicode 的实现方式 (最大特点是 变长的编码方式)

字符编码笔记:ASCII,Unicode 和 UTF-8

中日韩汉字Unicode编码表


源码注释:


alt

将源码中的16777619进制改为10进制,从字符串31415926中搜索4159:

4159

package main

import (
 "fmt"
 "strconv"
)

func main() {

 var primeRK uint32 = 10
 sep := "4159"
 hash := uint32(0)
 for i := 0; i < len(sep); i++ {

  //fmt.Println(sep[i])
  //fmt.Println(string(sep[i]))
  next, _ := strconv.Atoi(string(sep[i]))
  //hash = hash*primeRK + uint32(sep[i])
  hash = hash*primeRK + uint32(next)
  fmt.Println(hash)
 }
 
}

输出为:

4
41
415
4159

完整的以10为primeRK,从31415926中搜索4159的代码:

package main

import (
 "fmt"
 "strconv"
)

const PrimeRKNew = 10

func main() {
 str := `31415926`
 substr := "4159"

 fmt.Println("最终结果为:",  IndexRabinKarpNew(str, substr))
}

func HashStrNew(sep string) (uint32uint32) {
 hash := uint32(0)

 for i := 0; i < len(sep); i++ {
  //fmt.Println(sep[i])
  //fmt.Println(string(sep[i]))
  next, _ := strconv.Atoi(string(sep[i]))
  //hash = hash*primeRK + uint32(sep[i])
  hash = hash*PrimeRKNew + uint32(next)
  fmt.Println(hash)
 }

 var pow, sq uint32 = 1, PrimeRKNew
 for i := len(sep); i > 0; i >>= 1 {
  fmt.Println("i is:", i, "---""i&1 is:", i&1)
  if i&1 != 0 {
   pow *= sq
  }
  sq *= sq
  fmt.Println("pow is:", pow)
 }
 return hash, pow
}

func IndexRabinKarpNew(s, substr string) int {
 // Rabin-Karp search
 hashss, pow := HashStrNew(substr)
 fmt.Println("hashss, pow:", hashss, pow)

 fmt.Println("~~~分割线~~~")

 n := len(substr)
 var h uint32
 for i := 0; i < n; i++ {
  next1, _ := strconv.Atoi(string(s[i]))
  //h = h*PrimeRKNew + uint32(s[i])
  fmt.Println("next1 is:", next1)
  h = h*PrimeRKNew + uint32(next1)
 }

 fmt.Println("h即T串初始值为:", h)

 if h == hashss && s[:n] == substr {
  return 0
 }
 for i := n; i < len(s); {
  h *= PrimeRKNew
  fmt.Println("h*=:", h)

  last, _ := strconv.Atoi(string(s[i])) //当前T串的最后一个元素
  fmt.Println("last is:", last)
  //h += uint32(s[i])
  h += uint32(last)
  fmt.Println("h+=:", h)

  //h -= pow * uint32(s[i-n])
  first, _ := strconv.Atoi(string(s[i-n])) //当前T串的第一个元素
  fmt.Println("first is:", first)
  h -= pow * uint32(first)
  fmt.Println("h-=:", h)

  i++
  fmt.Println("---下次循环的 i为 ---", i)
  if h == hashss && s[i-n:i] == substr { //s[i-n:i]为当前的T串
   return i - n
  }
 }
 return -1
}

输出为:

4
41
415
4159
i is: 4 --- i&1 is: 0
pow is: 1
i is: 2 --- i&1 is: 0
pow is: 1
i is: 1 --- i&1 is: 1
pow is: 10000
hashss, pow: 4159 10000
~~~分割线~~~
next1 is: 3
next1 is: 1
next1 is: 4
next1 is: 1
h即T串初始值为: 3141
h*=: 31410
last is: 5
h+=: 31415
first is: 3
h-=: 1415
---下次循环的 i为 --- 5
h*=: 14150
last is: 9
h+=: 14159
first is: 1
h-=: 4159
---下次循环的 i为 --- 6
最终结果为: 2

strings.Contains()源码阅读暨internal/bytealg初探




书籍推荐

柔性字符串匹配


牛刀小试:

力扣28. 实现strStr()

力扣187. 重复的DNA序列

力扣686. 重复叠加字符串匹配



另:

除去KMP和RK算法,字符串匹配还有 Boyer-Moore算法(简称BM算法)系列算法,其核心思想是:

在字符串匹配过程中,模式串发现不匹配时,跳过尽可能多的字符以进行下一步的匹配,从而提高匹配效率

BM算法的简化版Horspool算法

以及性能更好的Sunday算法

Python用的也不是KMP,而是boyer-moore和horspool, 源码点此

KMP 算法的实际应用有哪些?

图解字符串匹配之Horspool算法和Boyer-Moore算法


本文由 mdnice 多平台发布

相关文章:

字符串匹配的Rabin–Karp算法

leetcode-28 实现strStr() 更熟悉的字符串匹配算法可能是KMP算法, 但在Golang中,使用的是Rabin–Karp算法 一般中文译作 拉宾-卡普算法,由迈克尔拉宾与理查德卡普于1987年提出 “ 要在一段文本中找出单个模式串的一个匹配&#xff0c;此算法具有线性时间的平均复杂度&#xff0…...

傅里叶变换(FFT)笔记存档

参考博客&#xff1a;https://www.luogu.com.cn/blog/command-block/fft-xue-xi-bi-ji 目录&#xff1a; FFT引入复数相关知识单位根及其相关性质DFT过程&#xff08;难点&#xff09;DFT结论&#xff08;重要&#xff09;IDFT结论&#xff08;重要&#xff09;IDFT结论证明&…...

ELK安装、部署、调试 (二) ES的安装部署

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎&#xff0c;基于RESTful web接口操作ES&#xff0c;也可以利用Java API。Elasticsearch是用Java开发的&#xff0c;并作为Apache许可条款下的开放源码发布&#xff0c;是当前流行的企业…...

Android 13 - Media框架(8)- MediaExtractor

上一篇我们了解了 GenericSource 需要依赖 IMediaExtractor 完成 demux 工作&#xff0c;这一篇我们就来学习 android media 框架中的第二个服务 media.extractor&#xff0c;看看 IMediaExtractor 是如何创建与工作的。 1、MediaExtractorService media.extractor 和 media.p…...

Flutter 混合开发调试

针对Flutter开发的同学来说&#xff0c;大部分的应用还是Native Flutter的混合开发&#xff0c;所以每次改完Flutter代码&#xff0c;运行整个项目无疑是很费时间的。所以Flutter官方也给我们提供了混合调试的方案【在混合开发模式下进行调试】&#xff0c;这里以Android Stud…...

C语言每日一练------(Day3)

本专栏为c语言练习专栏&#xff0c;适合刚刚学完c语言的初学者。本专栏每天会不定时更新&#xff0c;通过每天练习&#xff0c;进一步对c语言的重难点知识进行更深入的学习。 今天练习题的关键字&#xff1a; 尼科彻斯定理 等差数列 &#x1f493;博主csdn个人主页&#xff1a…...

14、监测数据采集物联网应用开发步骤(10)

监测数据采集物联网应用开发步骤(9.2) Modbus rtu协议开发 本章节在《监测数据采集物联网应用开发步骤(7)》基础上实现可参考《...开发步骤(7)》调试工具&#xff0c;本章节代码需要调用modbus_tk组件&#xff0c;阅读本章节前建议baidu熟悉modbus rtu协议内容 组件安装modb…...

Linux禅道上修改Apache 和 MySQL 默认端口号

1. 修改Apache默认端口号 80 cd /opt/zbox/etc/apachevim httpd.conf :wq 保存 2. 修改MySQL默认端口号 3306 cd /opt/zbox/etc/mysql vim my.cnf :wq 保存 3. 重启服务 ./zbox restart...

操作教程|通过1Panel开源Linux面板快速安装DataEase

DataEase开源数据可视化分析工具&#xff08;dataease.io&#xff09;的在线安装是通过在服务器命令行执行Linux命令来进行的。但是在实际的安装部署过程中&#xff0c;很多数据分析师或者业务人员经常会因为不熟悉Linux操作系统及命令行操作方式&#xff0c;在安装DataEase的过…...

机器学习策略——优化深度学习系统

正交化&#xff08;Orthogonalization&#xff09; 老式电视机&#xff0c;有很多旋钮可以用来调整图像的各种性质&#xff0c;对于这些旧式电视&#xff0c;可能有一个旋钮用来调图像垂直方向的高度&#xff0c;另外有一个旋钮用来调图像宽度&#xff0c;也许还有一个旋钮用来…...

ES6中Proxy和Proxy实例

1.Proxy Proxy 这个词的原意是代理&#xff0c;用在这里表示由它来“代理”某些操作&#xff0c;可以译为“代理器” 使用方法 let p new Proxy(target, handler);其中&#xff0c;target 为被代理对象。handler 是一个对象&#xff0c;其声明了代理 target 的一些操作。p 是…...

UDP协议的重要知识点

UDP&#xff0c;即用户数据报协议&#xff08;User Datagram Protocol&#xff09;&#xff0c;是一个简单的无连接的传输层协议。与TCP相比&#xff0c;UDP提供了更少的错误检查机制&#xff0c;并允许数据包在网络上更快地传输。在这篇博客中&#xff0c;我们将深入探讨UDP的…...

QT6为工程添加资源文件,并在ui界面引用

以添加图片资源为例 右键工程名字&#xff08;不是最上面的名字&#xff09;&#xff0c;点击添加现有文件 这种方式虽然添加到了工程中&#xff0c;但不能在UI设计界面完成引用。主要原因可能是未把文件放入到项目资源文件中&#xff0c;以下面一种方式可以看出区别。 点击添…...

Python小知识 - 如何使用Python的Flask框架快速开发Web应用

如何使用Python的Flask框架快速开发Web应用 现在越来越多的人把Python作为自己的第一语言来学习&#xff0c;Python的简洁易学的语法以及丰富的第三方库让人们越来越喜欢上了这门语言。本文将介绍如何使用Python的Flask框架快速开发Web应用。 Flask是一个使用Python编写的轻量级…...

Flutter 项目结构文件

1、Flutter项目的文件结构 先helloworld项目&#xff0c;看看它都包含哪些组成部分。首先&#xff0c;来看一下项目的文件结构&#xff0c;如下图所示。 2、介绍上图的内容。 -litb/main.dart文件&#xff1a;整个应用的入口文件&#xff0c;其中的main函数是整个Flutter应…...

未找到System.Runtime.InteropServices.Marshal.GetTypeFromCLSID(System.Guid) 方法错误

记录此问题实际上是由于.netFrame框架配置太高引起的&#xff0c;一般常见于二次开发中&#xff0c;因为二次开发一般都是引用的com组件&#xff0c;在引用过程中后台代码调用了 Method not found: System.Type System.Runtime.InteropServices.Marshal.GetTypeFromCLSID(Syste…...

人员位置管理,点亮矿山安全之路

矿山作为一个高危行业&#xff0c;安全问题一直备受关注。人员定位置管理是现代矿山安全管理的重要一环&#xff0c;可以帮助企业更好地实现对人员的实时监控和管理。因此&#xff0c;矿山人员位置管理系统对于矿山安全生产和管理非常重要&#xff0c;可以帮助减少安全事故的发…...

node-red - 读写操作redis

node-red - 读写操作redis 一、前期准备二、node-red安装redis节点三、node-red操作使用redis节点3.1 redis-out节点 - 存储数据到redis3.2 redis-cmd节点 - 存储redis数据3.3 redis-in节点 - 查询redis数据 附录附录1&#xff1a;redis -out节点示例代码附录2&#xff1a;redi…...

【图像处理】模板匹配的学习笔记

OpenCV的模板匹配算法 cv.TM_CCOEFFcv.TM_CCOEFF_NORMEDcv.TM_CCORRcv.TM_CCORR_NORMEDcv.TM_SQDIFFcv.TM_SQDIFF_NORMED 匹配代码模板 image cv2.imread(r"scene.png", cv2.IMREAD_GRAYSCALE) template cv2.imread(r"element.png", cv2.IMREAD_GRAYSC…...

Ext JS之Ext Direct快速入门

Ext Direct是一个专有名词, Direct是直接的意思。 Ext Direct 是 Ext JS 框架中的一个功能模块,用于简化前端 JavaScript 应用程序与后端服务器之间的通信和数据交换。 Ext Direct 提供了一种直接的、透明的方式来调用服务器上的方法和处理服务器响应,而无需编写大量的手动…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

渲染学进阶内容——模型

最近在写模组的时候发现渲染器里面离不开模型的定义,在渲染的第二篇文章中简单的讲解了一下关于模型部分的内容,其实不管是方块还是方块实体,都离不开模型的内容 🧱 一、CubeListBuilder 功能解析 CubeListBuilder 是 Minecraft Java 版模型系统的核心构建器,用于动态创…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

算法:模拟

1.替换所有的问号 1576. 替换所有的问号 - 力扣&#xff08;LeetCode&#xff09; ​遍历字符串​&#xff1a;通过外层循环逐一检查每个字符。​遇到 ? 时处理​&#xff1a; 内层循环遍历小写字母&#xff08;a 到 z&#xff09;。对每个字母检查是否满足&#xff1a; ​与…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...