算法学习笔记(14): 字符串哈希

字符串Hash

哈希是一个玄学的方法……最适骗分法

哈希,指将信息通过某种方式的缩减,映射到某一个值域上,从而表示这个信息。

如果有两个信息同时映射到了同一个位置,那么就会产生哈希冲突

哈希冲突在哈希表中有两种处理方式:

  • 链表

  • 质数后移(向后移动质数位,知道找到一个空的地方为止)

但是,在OI中,哈希冲突恰恰是毒瘤出题人卡你正确性的方法……关键是我们不一定能够保证没有哈希冲突……QwQ

所以,哈希很玄学,慎用!

字符串哈希

一般来说,字符串哈希在OI中常用的公式是 \(hash(str) = \sum_{i=1}^n base^{n-i} \times str_i\)

在生产环境中,可以有 time33, md5, sha256 等经典算法。但是这里用不到……

那么用这个公式有什么好处呢?

  • 可以通过 \(O(n)\) 的预处理,在 \(O(1)\) 得出任意一个子串的哈希值

  • 可以随意拼接两个字符串,在 \(O(1)\) 内得出合并后的哈希,并在 \(O(m)\) 时间内再处理

  • 可以扩展到二维甚至更高

  • ……

不扯了……讲实现了

由于我们需要映射到某一个值域上,所以,一般来说,我们取为 unsigned long long 可以表示的值域即可。(这样也有一些其他的好处,自然溢出避免了超慢的取模运算)

那么,我们以字符串 jeefybase13 为例:

Text Hash Calc
j 106 \(0 \times 13\) + 'j'
je 1479 \(106 \times 13 +\) ’e'
jee 19328 \(1479 \times 13\) + 'e'
jeef 251366 \(19328 \times 13\) + 'f'
jeefy 3267897 \(251366 \times 13\) + 'y'

生成代码如下

我们考虑换一种表示法:

Text Calc
j \(13^0 + ord(j)\)
je \(13^1 \times ord(j) + 13^0 \times ord(e)\)
jee \(13^2 \times ord(j) + 13^1 \times ord(e) + 13^0 \times ord(e)\)
jeef \(13^3 \times ord(j) + 13^2 \times ord(e) + 13^1 \times ord(e) + 13^0 \times ord(f)\)
jeefy \(13^4 \times ord(j) + 13^3 \times ord(e) + 13^2 \times ord(e) + 13^1 \times ord(f) + 13^0 \times ord(y)\)

想必,有了这个表之后,哈希拼接应该就很简单了吧。

\[Hash(T) = Hash(A) \times 13^{|B|} + Hash(B) \]

\(|B|\) 指的是字符串的长度

我们可以预处理出 \(base^i\)

hashInt bofs[N] = {1}; // base_offset
for (int i = 1; i < N; ++i) bofs[i] = bofs[i - 1] * base;

那么两个计算如下

struct String {
    string s;
    hashInt ha;
}

String merge(String A, String B) {
    String s = {A.s + B.s, A.ha * bofs[B.s.size()] + B.ha};
    return s;
}

没有实际运行过程序,请自行斟酌

同理,如果我们需要字符串片段的哈希,我们可以通过合并的逆操作……

hashInt ha[N];
hashInt slice(int l, int r) { // [l, r]
    return ha[r] - ha[l - 1] * bofs[r - l + 1];
}

那么,恭喜你,掌握了哈希的大部分用法了。

房卡小专题

总所周知,哈希是出题人特别喜欢卡的一种做法,所以,我们需要较少减少哈希冲突的可能。那么比较好的解决方法是双哈希。而双哈希指的是双模数和双底数,也就是说值域和 \(base\) 都不一样。这种双保险的方法是很难被卡的。

练习题

[CTSC2014] 企鹅 QQ - 洛谷

【模板】树同构([BJOI2015]树的同构) - 洛谷

没想到吧,同构也可以通过哈希来!

[JSOI2008]Blue Mary的战役地图 - 洛谷

这道题可以用二维哈希

小知识

其实C++也是有内置的哈希函数的,参考std::hash - cppreference.com

posted @ 2023-02-06 21:07  jeefy  阅读(70)  评论(0编辑  收藏  举报