字符串哈希算法详解:原理、实现与应用
字符串哈希是一种高效处理字符串匹配和比较的技术,它通过将字符串映射为一个唯一的数值(哈希值),从而在O(1)时间内完成子串的比较。本文将结合代码实现,详细讲解前缀哈希法的工作原理,并通过流程图逐步解析其执行过程。
. 字符串哈希的核心思想
字符串哈希的核心目标是:
-
将任意长度的字符串转换为固定大小的哈希值。
-
支持快速比较两个子串是否相同(时间复杂度O(1))。
-
适用于大规模文本处理(如DNA序列比对、 plagiarism检测等)。
1.1 哈希函数设计
常用的字符串哈希方法是多项式滚动哈希(Polynomial Rolling Hash),其公式为:
H(S)=(S[0]×Pn−1+S[1]×Pn−2+⋯+S[n−1]×P0)mod MH(S)=(S[0]×Pn−1+S[1]×Pn−2+⋯+S[n−1]×P0)modM
其中:
-
PP 是一个质数(通常取131或13331)。
-
MM 是一个大数(如 264264,代码中用
unsigned long long自然溢出替代取模)。
2. 代码实现解析
以下是基于前缀哈希的字符串匹配代码(支持快速比较任意两个子串):
2.1 变量定义
#include <stdio.h> #include <string.h>#define N 100010 #define P 131 // 经验值,减少冲突typedef unsigned long long Ull;Ull h[N]; // h[i]存储前i个字符的哈希值 Ull p[N]; // p[i]存储P的i次幂
2.2 初始化哈希数组
int main() {int n, m;char str[N];scanf("%d%d", &n, &m);scanf("%s", str + 1); // 从str[1]开始存储p[0] = 1;for (int i = 1; i <= n; i++) {p[i] = p[i - 1] * P; // 计算P^ih[i] = h[i - 1] * P + str[i]; // 计算前i个字符的哈希值}// ...后续处理查询 }
初始化过程详解
-
p[i] = P^i:预计算幂次,用于后续子串哈希计算。 -
h[i] = h[i-1] * P + str[i]:递推计算前缀哈希值。
示例(假设 str = "ABC",P=131):
-
h[0] = 0 -
h[1] = h[0]*131 + 'A' = 65 -
h[2] = h[1]*131 + 'B' = 65*131 + 66 = 8581 -
h[3] = h[2]*131 + 'C' = 8581*131 + 67 = 1123988
2.3 子串哈希计算
Ull get(int l, int r) {return h[r] - h[l - 1] * p[r - l + 1]; }
公式解析
H(S[l..r])=H(r)−H(l−1)×Pr−l+1H(S[l..r])=H(r)−H(l−1)×Pr−l+1
-
h[r]:前r个字符的哈希值。 -
h[l-1] * p[r-l+1]:前l-1个字符的哈希值左移到对齐位置。
示例(计算 "BC" 在 "ABC" 中的哈希值):
-
get(2, 3) = h[3] - h[1]*p[2] = 1123988 - 65*17161 = 1123988 - 1115465 = 8523
2.4 查询处理
while (m--) {int l1, r1, l2, r2;scanf("%d%d%d%d", &l1, &r1, &l2, &r2);if (get(l1, r1) == get(l2, r2))printf("Yes\n");elseprintf("No\n"); }
能:比较两个子串 str[l1..r1] 和 str[l2..r2] 是否相同。
3. 流程图详解
以下是代码执行的流程图:
graph TDA[开始] --> B[输入n,m和字符串str]B --> C[初始化p[0]=1, h[0]=0]C --> D[循环i=1到n]D --> E[计算p[i] = p[i-1] * P]E --> F[计算h[i] = h[i-1] * P + str[i]]F --> DD --> G[输入查询次数m]G --> H[循环m次]H --> I[输入l1,r1,l2,r2]I --> J[计算Hash1=get(l1,r1)]I --> K[计算Hash2=get(l2,r2)]J --> L{Hash1 == Hash2?}K --> LL --> |Yes| M[输出"Yes"]L --> |No| N[输出"No"]M --> HN --> HH --> O[结束]
4. 关键问题解答
4.1 为什么选择P=131?
-
131是一个经验值,满足:
-
足够大以减少冲突。
-
是质数,保证哈希分布均匀。
-
-
其他常见选择:13331、99991等。
4.2 如何处理哈希冲突?
-
理论上,
unsigned long long自然溢出相当于模 264264,冲突概率极低。 -
如果需绝对准确,可双哈希(用两个不同的P计算)。
4.3 时间复杂度分析
| 操作 | 时间复杂度 |
|---|---|
| 初始化哈希数组 | O(n) |
| 单次子串比较 | O(1) |
| m次查询 | O(m) |
5. 应用场景
-
快速子串匹配(如Rabin-Karp算法)。
-
最长回文子串(结合二分搜索)。
-
文本去重(比较哈希值而非原始字符串)。
6. 完整代码
#include <stdio.h> #include <string.h>#define N 100010 #define P 131typedef unsigned long long Ull;Ull h[N], p[N];Ull get(int l, int r) {return h[r] - h[l - 1] * p[r - l + 1]; }int main() {int n, m;char str[N];scanf("%d%d", &n, &m);scanf("%s", str + 1);p[0] = 1;for (int i = 1; i <= n; i++) {p[i] = p[i - 1] * P;h[i] = h[i - 1] * P + str[i];}while (m--) {int l1, r1, l2, r2;scanf("%d%d%d%d", &l1, &r1, &l2, &r2);if (get(l1, r1) == get(l2, r2))printf("Yes\n");elseprintf("No\n");}return 0; }
-
字符串哈希通过前缀哈希+幂次预处理实现O(1)子串比较。
-
P的选择和自然溢出是关键优化点。
-
适用于需要频繁比较子串的场景,比直接暴力匹配高效得多。
相关文章:
字符串哈希算法详解:原理、实现与应用
字符串哈希是一种高效处理字符串匹配和比较的技术,它通过将字符串映射为一个唯一的数值(哈希值),从而在O(1)时间内完成子串的比较。本文将结合代码实现,详细讲解前缀哈希法的工作原理,并通过流程图逐步解析…...
vue2(webpack)集成electron和 electron 打包
前言 之前发过一篇vue集成electron的文章,但是用vue3vite实现的,在vue2webpack工程可能不适用,所以这篇文章就主要介绍vue2webpack集成electron方法 创建项目 vue create vue-electron-demo目录架构 vue-electron-demo/ ├── src/ …...
C++内存管理优化实战:提升应用性能与效率
🧑 博主简介:CSDN博客专家、CSDN平台优质创作者,高级开发工程师,数学专业,拥有高级工程师证书;擅长C/C、C#等开发语言,熟悉Java常用开发技术,能熟练应用常用数据库SQL server,Oracle…...
redis数据迁移之通过redis-dump镜像
这里写目录标题 一、redis-dump 镜像打包1.1 安装windows docker1.2 idea项目创建1.3 idea镜像打包 二、redis数据迁移2.1 数据导出2.2 数据导入 一、redis-dump 镜像打包 没有找到可用的redis-dump镜像,需要自己打包一下,这里我是在idea直接打包的 1.…...
C语言单链表的增删改补
目录 (一)单链表的结构定义及初始化 (二)单链表的尾插,头插 (三)单链表的尾删,头删 (四)单链表的查找,删除,销毁 单链表是数据结构课程里的第二个数据结构。单链表在逻辑结构是连续的,在物理…...
redis导入成功,缺不显示数据
SpringBootTest class SecurityApplicationTests {AutowiredStringRedisTemplate template; //添加这句代码,自动装载,即可解决文章三处代码报错Testvoid contextLoads() {String compact Jwts.builder().signWith(Jwts.SIG.HS512.key().build()).subj…...
从表格到序列:Swift 如何优雅地解 LeetCode 251 展开二维向量
文章目录 摘要描述题解答案题解代码分析示例测试及结果时间复杂度空间复杂度总结 摘要 在这篇文章中,我们将深入探讨 LeetCode 第 251 题——“展开二维向量”的问题。通过 Swift 语言,我们不仅会提供可运行的示例代码,还会结合实际场景进行…...
汇丰xxx
1. Spring Boot 的了解,解决什么问题? 我的理解: Spring Boot 是一个基于 Spring 框架的快速开发脚手架,它简化了 Spring 应用的初始搭建和开发过程。解决的问题: 简化配置: 传统的 Spring 应用需要大量的…...
Spring MVC与Spring Boot文件上传配置项对比
Spring MVC与Spring Boot文件上传配置项对比 一、Spring MVC配置项(基于不同MultipartResolver实现) 1. 使用 CommonsMultipartResolver(Apache Commons FileUpload) Bean public MultipartResolver multipartResolver() {Common…...
小型园区网实验
划分VLAN SW3 [sw3]vlan batch 2 3 20 30 [sw3]interface GigabitEthernet 0/0/1 [sw3-GigabitEthernet0/0/1]port link-type access [sw3-GigabitEthernet0/0/1]port default vlan 2 [sw3-GigabitEthernet0/0/1]int g0/0/2 [sw3-GigabitEthernet0/0/2]port link-type acces…...
c# 数据结构 链表篇 有关单链表的一切
本人能力有限,本文仅作学习交流与参考,如有不足还请斧正 目录 0.单链表好处 0.5.单链表分类 1.无虚拟头节点情况 图示: 代码: 头插/尾插 删除 搜索 遍历全部 测试代码: 全部代码 2.有尾指针情况 尾插 全部代码 3.有虚拟头节点情况 全部代码 4.循环单链表 几个…...
VS Code连接服务器编写Python文件
1、下载 Visual Studio Code 2、打开扩展(ctrl shift x ) 3、搜索 Remote - SSH,安装 4、F1 或者 点金左下角 5、选择:Remote-SSH: Connect to Host……,回车 6、第一次用的时候,VS Code 会提示添加 SSH 主机。输…...
图解AUTOSAR_SWS_FlexRayNetworkManagement
FlexRay网络管理详解 AUTOSAR标准FlexRay网络管理模块技术说明 目录 1. FlexRay网络管理概述 1.1 模块功能与目的1.2 适用范围与限制2. FlexRay网络管理架构 2.1 模块层次结构2.2 组件交互关系3. FlexRay网络管理状态机 3.1 状态转换机制3.2 主要状态说明4. FlexRay网络管理通信…...
Gitea的安装和配置以及应用
Gitea的安装和配置以及应用 一、安装 1、创建数据库和数据库账户(pg) su – postgres -c "psql" CREATE ROLE gitea WITH LOGIN PASSWORD gitea; CREATE DATABASE giteadb WITH OWNER gitea TEMPLATE template0 ENCODING UTF8 LC_COLLATE …...
Blender 转 STL 文件全攻略:从基础到进阶
在 3D 建模与打印领域,Blender 凭借其强大的功能和开源特性,深受创作者喜爱。而 STL 文件格式,作为 3D 打印行业的通用标准,能被绝大多数 3D 打印软件和设备所识别。因此,将 Blender 模型转换为 STL 文件,是…...
UI自动化基础(1)
1、pip install selenium4.3.0,最好指定版本安装,因为不同的版本可能会有一些兼容 性的问题。 2、pip uninstall urllib3 ,pip install urllib31.26.15 【执行版本安装】,goole是114.版本 3、装好浏览器,正确安装。最好…...
$_GET变量
$_GET 是一个超级全局变量,在 PHP 中用于收集通过 URL 查询字符串传递的参数。它是一个关联数组,包含了所有通过 HTTP GET 方法发送到当前脚本的变量。 预定义的 $_GET 变量用于收集来自 method"get" 的表单中的值。 从带有 GET 方法的表单发…...
TBE(TVM的扩展)
算子 张量 一个张量只有一种数据类型 在内存中只能线性存储,最终形成一个长的一维数组 晟腾AI的数据格式 AIPP是对我们常见的数据格式转化成AI core支持的数据格式 广播机制 TVM TBE的第一种开发方式:DSL TBE的第二种开发方式:TVM TBE的第…...
【Function Calling与Tool Calling】深度解析大模型智能中枢的架构革命
目录 一、范式转移:从对话引擎到智能中枢 二、核心技术解析 2.1 Function Calling技术栈 2.2 Tool Calling实现模式 三、企业级应用架构设计 3.1 智能工单系统案例 3.2 性能优化策略 四、安全与治理框架 4.1 权限控制矩阵 4.2 审计追踪设计 五、开发者实…...
知识表示方法之六:过程表示法(Procedural Representation)
在人工智能的发展史中,关于知识的表示方法曾存在两种不同的观点。一种观点认为知识主要是陈述性的,其表示方法应着重将其静态特性,即事物的属性以及事物间的关系表示出来,称以这种观点表示知识的方法为陈述式或说明式表示法&#…...
Java 中序列化和反序列化
Java 中的序列化(Serialization)和反序列化(Deserialization)是将对象和二进制数据(或其他格式)之间转换的过程,常见于对象传输、缓存、持久化等场景。 下面是 Java 中常见的几种 序列化/反序列…...
sql-labs靶场 less-2
文章目录 sqli-labs靶场less 2 联合注入 sqli-labs靶场 每道题都从以下模板讲解,并且每个步骤都有图片,清晰明了,便于复盘。 sql注入的基本步骤 注入点注入类型 字符型:判断闭合方式 (‘、"、’、“”…...
Spring配置部分
Spring配置部分 单纯的使用Spring可以通过配置文件xml,配置注解,全注解方式执行 无论使用哪种方式,都需要在Main方法中加载配置(配置文件或者注解)获取到Spring容器,在通过容器的GetBean方法获取Bean对象…...
git clone(复制)下载
1、复制 下载地址 2、打开网页,点击 克隆/下载按扭 3、按提示复制命令行到终端 4、VS里打开终端,并粘贴以下命令 5、 下载完毕 6、复制文件夹到你选定的位置 7、用VSCODE打开文件夹,开始你接下来的工作...
Android设置adjustResize时无法生效 解决办法
删除Activity类下执行全屏的一行参数。 将图中这段Activity类中执行命令给删除就解决了。 注意关闭后状态栏和导航栏的透明度就无法自动处理了,需要到values和values-night下的themes.xml手动设置状态栏背景颜色。 <item name"android:statusBarColor"…...
按键长按代码
这些代码都存放在定时器中断中。中断为100ms中断一次。 数据判断,看的懂就看吧...
Idea将Java工程打包成war包并发布
1、问题概述? 项目开发之后,我们需要将Java工程打包成war后缀,并进行发布。之前在网上看到很多的文章,但是都不齐全,今天将提供一个完整的实现打包war工程,并发布的文章,希望对大家有所帮助,主要解决如下问题: 1、war工程需要满足的相关配置 2、如何解决项目中的JDK…...
SGLang实战问题全解析:从分布式部署到性能调优的深度指南
引言:当高性能推理遇上复杂生产环境 在大型语言模型(LLM)的生产部署中,SGLang以其革命性的RadixAttention和结构化编程能力,正成为越来越多企业的首选推理引擎。然而,当我们将32B/70B级别的大模型部署到实际生产环境时࿰…...
优选算法第八讲:链表
优选算法第八讲:链表 1.链表常用操作和技巧总结2.两数相加3.两两交换链表中的节点4.重排链表5.合并k个升序链表6.k个一组翻转链表 1.链表常用操作和技巧总结 2.两数相加 3.两两交换链表中的节点 4.重排链表 5.合并k个升序链表 6.k个一组翻转链表...
Python语言的需求分析
Python语言的需求分析 引言 在信息技术快速发展的今天,编程语言的选择对于软件开发的成功与否起着至关重要的作用。Python作为一种高级编程语言,以其简洁易读的语法和强大的功能受到越来越多开发者的青睐。通过对Python语言的需求分析,我们…...
