字符串哈希
进制哈希
BKDRHash哈希函数
字符串哈希:$\color{red}{构造一个数字使之唯一代表一个字符串}$。但是为了将映射关系一一对应,也就是,一个字符串代表一个数字,那么一个数字也对应一个字符串。
我们希望这一个映射是个单射,即保证任意的字符串对应的数字是唯一的,也就是不出现一个数字对应两个字符串等情况。
BKDRHash
BKDRHash是一种“进制哈希”,计算步骤非常简单。设定一个进制\(P\),需要计算一个字符串的哈希值时,把每个字符看作每个进制位上的一个数字,这个串转换为一个基于进制P的数,最后对\(M\)取余数,就得到了这个字符串的哈希值。
注意:
由于得到的哈希值都很大,不能直接映射到一个巨大的空间上,所以一般都需要限制空间。方法是取余,把得到的哈希值对一个设定的空间大小\(M\)取余数,以余数作为索引地址。当然这样做可能产生冲突问题。
编程时可以采用一种隐性取余的方法。取空间大小为\(M=2^{64}\),64是unsigned long long 型的长度,一个unsigned long long型的哈希值\(H\),当\(H>M\)时会自动溢出,等价于自动对\(M\)取余,这样可以避免低效的取余运算。
举例子:
以字符串“abc”为例,令进制\(P=131\),有以下两种方法。
\(1:\)把每个字符看作一个数字,即\(a=1,b=2,c=3....z=26\),然后把字符串的每位按进制\(P\)的权值相加得\('a' *131^2+'b'*131^1+'c'*131^0=17426\)
\(2.:\)把每个字符的ASCII码直接看成代表它的数字也可以,计算得\('a' *131^2+'b'*131^1+'c'*131^0=1677554\)
进制P常用的值有\(31、131、1313、13131、131313\)等,用这些数值可以有效避免碰撞。
由于常常会碰到到字符串匹配的题目中,所以验证某两段子串是否相等这个方法很重要
#include <bits/stdc++.h>
using namespace std;
using u64 = unsigned long long;
u64 base = 13331;
vector<u64>p, hx; //p存进制位,hx存当前字符串长度的哈希值
//也可以把hx理解成前缀和数组
void Hash(string &s) {
s = " " + s;
int N = s.size();
p.resize(N + 1), hx.resize(N + 1);
p[0] = 1, hx[0] = 0;
for (int i = 1; i < s.size(); i++) {
p[i] = p[i - 1] * base; //存进制数
hx[i] = hx[i - 1] * base + s[i]; //字符串哈希
}
}
u64 get(int l, int r) { //获取子串的哈希,常用来字符串匹配
return hx[r] - hx[l - 1] * p[r - l + 1];
}
//检查两个子串是否相等
bool same(int l1, int r1, int l2, int r2) {
return get(l1, r1) == get(l2, r2);
}
int main() {
}
模版题P3370 【模板】字符串哈希
理解思想和方法,灵活的选择和调整自己的模板!!!
省赛难题D. Period
posted on 2024-07-26 13:06 swj2529411658 阅读(8) 评论(0) 编辑 收藏 举报