字符串Hash (学习笔记)

引入

想象你现在有一堆数,你要把他们装进一堆桶里,
相同的数放在一起,你会怎么做呢?

只要在每个桶上面标上这个数,然后把数丢进相应的桶不就完了?

在程序中,我们使用桶排的思路记录。但是,当在考虑一个很大的数值时,又如何记录。

或者直接来一个字符串,又如何记录呢?

难道要开一个字符串下标数组?怎么可能。

Hash

Hash算法是通过一个Hash函数,

将一种数据(包括字符串,较大的数等)转化成为能够用变量表示或是直接就可以作为数组下标的数,

通过Hash函数转化得到数值我们称之为Hash值。

通过Hash值可以实现块石查找和匹配。以下我们一起来探究以下Hash的两种运用:

字符串HashHash表

【实现方法】

首先取一个固定值P(为模数),将字符串中的每一种字符(或序列中的每一种数)映射成小于P的整数。

那么可以把字符串(或序列)看成P进制数。

一般来说,我们分配的数值都远小于P。

例如:对于小写字母构造的字符串,可以令a = 1, b = 2, c = 3..., z = 26.

取一固定值M, 求出P进制对M的余数,作为该字符串的Hash值。

一般来说,我们取 P = 131 或 P = 13331,此时Hash值是很难冲突的。

一般认为两个串的Hash值相同,即冲突。

对于字符串的各种操作,都可以直接对P进制进行算术运算映射Hash值上。

大家听懂了吗?窝自己都觉得好抽象,下面举例说明一下:

S = "abc", c = "d", T = "xyz"
S表示为P进制数: 1 2 3
H(S)= 1 * P^2 + 2 * p + 3

字符串Hash对于任意不同的字符串是不是都不会发生冲突呢?

显然不是的。我们常常认为OI的题目不会出现不同字符串相同Hash值得情况,

实际上根据生日悖论, 对于Hash值在[0,n]内均匀分布的Hash函数,

在数据随机的情况下不发生冲突的数据期望个数为 sqrt(n),

这在选择哈希函数时可以作为一个效率和正确性的参考。

即便如此, 我们还可以再用“双哈希”降低重复得概率,即取不同的模数,

把不同的模数,算出的哈希值都记下来,只有几个哈希值都一样,

我们才能判断字符串相同。

通常常用双哈希就可以将冲突降到很低,

通常取M = 10^9 + 7 和 10^7 + 9,因为他们是一对“孪生质数”。

单将概念我相信应该没有几个人看懂把(乱猜的),

还是必须通过题目分析:一些例题

题解:link

posted @ 2021-01-29 18:30  Viktley  阅读(271)  评论(0)    收藏  举报