笔记 字符串哈希
(2023.11.02 第一次发布于洛谷博客)
大概也就是抄了个简洁版。
文前给大家找点乐子:
西江月·证明
即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立。略去过程Q.E.D.,由上可知证毕。
什么是哈希
文艺一点的说法: 哈希表又称散列表,一种以「key-value」形式存储数据的数据结构。所谓以「key-value」形式存储数据,是指任意的键值 key 都唯一对应到内存中的某个位置。只需要输入查找的键值,就可以快速地找到其对应的 value。可以把哈希表理解为一种高级的数组,这种数组的下标可以是很大的整数,浮点数,字符串甚至结构体。
by OI-Wiki简单来说: 也就是你使用
std::map实现的功能。
如何构造哈希
一个例子:将字符串视为一个 \(26\) 进制的数,即 a~z 视为 1~26。
选取两个互质的数 \(b\) 和 \(h\ (b\lt h)\),其中 \(b\) 为基数,\(h\) 为模数。为了降低冲突概率,\(h\) 要求尽量大,一般来说 \(b=131\) 或 \(13331,h=2^{64}\)。
在 \(h=2^{64}\) 时,取模操作可以利用
unsigned long long类型的自然溢出完成。
假定字符串 \(C=c_1c_2c_3\dots c_m\),则哈希函数为:
\(H(C)=(c_1\times b^{m-1}+c_2\times b^{m-2}+\dots+c_m\times b^0)\)。
滚动哈希优化
用于在 \(O(1)\) 时间复杂度下取出子串 \([l,r]\) 的 hash 值。
设 \(H(k)\) 为字符串 \(C\) 前 \(k\) 个字符构成字串的哈希值,显然有:
\(H(k)=H(k-1)\times b+c_{k}\)(这个似乎更像人话)
那么可得:
\(H(r)=c_1\times b^{r-1}+\dots+c_{l-1}\times b^{r-l-1}+\color{blue}c_l\times b_{r-l}+\dots+c_r\times b^0\)
\(H(l-1)=c_1\times b^{l-2}+\dots+c_{l-1}\times b^0\)
那么借鉴前缀和的思路,则有:
\(H(l,r)=H(r)-H(l-1)\times b^{r-l+1}\)
时间复杂度 \(O(n+m)\)。

浙公网安备 33010602011771号