哈希算法入门

序列哈希(字符串哈希)

概念

序列哈希是用于判断两个字符串/数列是否相等的工具

对于字符串\(S\),他的哈希计算公式为

\(hash(S)=\sum_{i=1}^{|S|}S[i]\times base^{i}\)

但是由于涉及指数运算与乘积,容易造成溢出.所以我们一般需要取模

\(hash(S)=(\sum_{i=1}^{|S|}S[i]\times base^{i}) \bmod p\)

序列哈希(字符串哈希)的特点在于

  • 有序性(同样字符构成的不同排列通常会产生不同的哈希值)

  • 方便取区间哈希值

常见计算方法

为了方便取字串的哈希值,我们通常构造哈希前缀和 \(h\)

\(h[x]=(h[x-1]\times base+S[x])\bmod p\)

展开可得

\(h[x]=(\sum_{i=1}^{x}S[i]\times base^{x-i})\bmod p\)

同时我们预处理\(base\)的幂

\(pow[x]=base^x\bmod p\)

对于\(S\)的区间\([l,r]\)的哈希计算

\(hash(S_{[l,r]})=(\sum_{i=l}^{r}S[i]\times base^{r-i})\bmod p\)

等价于

\(hash(S_{[l,r]})=(h[r]-h[l-1]\times pow[r-l+1])\bmod p\)

这样我们就可以\(O(n)\)预处理\(O(1)\)求出任意字串的哈希值了

这种方法不需要使用逆元,因此在竞赛中更加常用

子集哈希

子集哈希主要用于判断两个集合是否相等,或者快速判断两个集合之间的关系

对于每个可能出现的元素\(x\),我们随机分配一个哈希值\(val[x]\)

对于一个集合\(S\),定义

\(hash(S)=\sum_{x\in S}val[x]\)

为了防止数值过大,通常需要取模

\(hash(S)=(\sum_{x\in S}val[x])\bmod p\)

子集哈希的特点在于

  • 无序性(集合中元素的排列顺序不会影响哈希值)

  • 可以方便地进行集合的合并与删除

  • 可以用于快速判断两个集合是否相等

例如有两个集合\(A,B\),如果

\(hash(A)=hash(B)\)

则认为\(A=B\)

对于集合的并集,如果\(A,B\)没有重复元素,则有

\(hash(A\cup B)=hash(A)+hash(B)\)

对于删除元素\(x\),可以直接进行

\(hash(S\setminus{x})=hash(S)-val[x]\)

因此子集哈希特别适合处理集合的增删以及集合相等性判断

不过需要注意,子集哈希同样存在哈希碰撞,因此\(hash(A)=hash(B)\)并不能严格证明\(A=B\)

指数哈希

指数哈希可以看作子集哈希的一种特殊形式,主要用于判断两个集合是否相等

对于每个元素\(x\),我们使用\(base^x\)作为其哈希值

对于一个集合\(S\),定义

\(hash(S)=\sum_{x\in S}base^x\)

为了防止数值过大,通常需要取模

\(hash(S)=(\sum_{x\in S}base^x)\bmod p\)

指数哈希的特点在于

  • 无序性(集合中元素的排列顺序不会影响哈希值)

  • 不同元素具有不同的权值

  • 可以方便地进行集合的合并与删除

例如有两个集合\(A,B\),如果

\(hash(A)=hash(B)\)

则认为\(A=B\)

对于加入元素\(x\),可以进行

\(hash(S\cup{x})=hash(S)+base^x\)

对于删除元素\(x\),可以进行

\(hash(S\setminus{x})=hash(S)-base^x\)

因此指数哈希特别适合处理集合相等性判断以及集合的增删

指数哈希本质上仍然属于子集哈希,只不过将元素\(x\)的哈希值固定为\(base^x\)

需要注意,指数哈希同样存在哈希碰撞,因此\(hash(A)=hash(B)\)并不能严格证明\(A=B\)

异或哈希

异或哈希与子集哈希类似,也是通过给每个元素分配一个随机值来表示一个集合

对于每个元素\(x\),随机生成一个哈希值\(val[x]\)

对于集合\(S\),定义

\(hash(S)=\bigoplus_{x\in S}val[x]\)

其中\(\oplus\)表示按位异或

异或哈希的特点在于

  • 无序性(元素的排列顺序不会影响哈希值)

  • 可以方便地进行集合的添加与删除

  • 不需要取模,因为异或本身不会产生传统意义上的溢出问题

利用异或的性质

\(x\oplus x=0\)

\(x\oplus0=x\)

\(x\oplus y\oplus y=x\)

因此对于集合\(S\),加入元素\(x\)时

\(hash(S\cup{x})=hash(S)\oplus val[x]\)

删除元素\(x\)时同样可以直接进行

\(hash(S\setminus{x})=hash(S)\oplus val[x]\)

这是因为

\(val[x]\oplus val[x]=0\)

例如有两个集合\(A,B\),可以通过

\(hash(A)\oplus hash(B)\)

得到两个集合中出现次数不同的元素对应的哈希值

如果\(A,B\)完全相同,则

\(hash(A)\oplus hash(B)=0\)

三种哈希的区别

序列哈希主要用于处理有序序列

\(hash(S)=\sum S[i]\times base^{i}\)

元素的位置会影响哈希值

子集哈希主要用于处理无序集合

\(hash(S)=\sum_{x\in S}val[x]\)

元素的顺序不会影响哈希值

指数哈希同样用于处理无序集合

\(hash(S)=\sum_{x\in S}base^x\)

可以看作子集哈希的一种特殊形式

异或哈希同样主要用于处理无序集合

\(hash(S)=\bigoplus_{x\in S}val[x]\)

但是异或哈希利用了异或的性质,可以非常方便地进行元素的加入和删除

简单来说

  • 序列哈希:关注顺序

  • 子集哈希:不关注顺序,通过加法维护

  • 指数哈希:不关注顺序,使用\(base^x\)作为元素权值

  • 异或哈希:不关注顺序,通过异或维护

posted @ 2026-10-04 19:55  txp2025  阅读(4)  评论(0)    收藏  举报