字符串Hash (学习笔记)
引入
想象你现在有一堆数,你要把他们装进一堆桶里,
相同的数放在一起,你会怎么做呢?
只要在每个桶上面标上这个数,然后把数丢进相应的桶不就完了?
在程序中,我们使用桶排的思路记录。但是,当在考虑一个很大的数值时,又如何记录。
或者直接来一个字符串,又如何记录呢?
难道要开一个字符串下标数组?怎么可能。
Hash
Hash算法是通过一个Hash函数,
将一种数据(包括字符串,较大的数等)转化成为能够用变量表示或是直接就可以作为数组下标的数,
通过Hash函数转化得到数值我们称之为Hash值。
通过Hash值可以实现块石查找和匹配。以下我们一起来探究以下Hash的两种运用:
字符串Hash 和 Hash表。
【实现方法】
首先取一个固定值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