字符串哈希笔记
字符串哈希
1. 定义
一个把字符串映射到整数的函数,这个被称为哈希函数;
这个函数的作用:希望可以判断两个字符是否相等;
1.1 Hash的思想
核心思想在于:
如何将一个字符串映射到一个值域较小、方便比较的范围?
大范围映射到小范围:
对一个大数进行取模,例如一个大的质数
注意:
- 在字符串哈希中,值域需要小到能够快速比较, 例如 或者 都是可以快速比较的)
哈希性质:
- 若Hash值不一样,那么两个字符串一定不相等;
- 若Hash值一样,那两个字符串不一定相等,当时大概率一样;
将 Hash 函数值一样但原字符串不一样的现象称为哈希碰撞。
1.2 Hash的计算和改进
哈希需要关注的有时间复杂度和Hash的准确率
对于一个长度为L
的字符串s
来说,可以这样定义Hash的表达式如下:
即对于字符串s = "xyz"
来说,如下计算
0 | 1 | 2 |
---|---|---|
x | y | z |
其中哈希值计算公式为: ,可以理解为一个P进制的计算;
经验选择:
- , 即
unsigned long long
类型的最大取值范围; - 或者
1.3 自己的常用实现
具体例子: 字符串S为,把字符串变成一个P进制数字,具体方法如下:
为了方便计算P[N],可以提前计算好每个值,如下:
typedef unsigned long long ULL;
const int N = 1E5+7;
const int p = 131;
ULL P[N], s[N];
void init() {
P[1] = 1;
for (int i = 2; i <= N; i++)
P[i] = P[i-1] * p;
}
求一个字符串的哈希值就相当于求前缀和,求一个字符串的子串哈希值就相当于求部分和;
前缀和公式:
区间和公式:
字符串中求子串的哈希的区间和公式的理解:
ABCDEF
和ABC
的前三个字符串一样,那么子串DEF
的哈希值计算可以理解为ABC
的哈希值 * P^2变成ABC000
,则俩式做减法即可得DEF
的哈希值
代码的简单实现如下:
unsigned long long getHash(int l ,int r) {
return h[r] - h[l-1] * P[r-l+1];
}
2. 代码实现
2.1 暴力版本:
#include <iostream>
#include <cstring>
typedef unsigned long long ULL;
const int N = 1E5+7;// 字符串最大长度
const int b = 131;
const int M = 1E9+7;
ULL getHash(const string &s) {
ULL res = 0;
for (int i = 0; i < s.size(); i++) {
res = (s[i] + res * b) % M; // 这里如果越界了,即等于 Mod 2^64
}
return res;
}
2.2 字符串前缀和哈希
typedef unsigned long long ULL;
const int N = 1E5+7;
const int p = 131;
ULL P[N], s[N];
void init(int n) {
P[0] = 1;
for (int i = 0; i < n; i++)
P[i+1] = P[i] * p;
h[i+1] = h[i] * p + s[i];
}
unsigned long long getHash(int l ,int r) {
return h[r] - h[l-1] * P[r-l+1];
}
参考文档
作者:醉曦
欢迎任何形式的转载,但请务必注明出处。
限于本人水平,如果文章和代码有表述不当之处,还请不吝赐教。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效