字符串哈希

进制哈希

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编辑  收藏  举报

导航