首页 > 其他分享 >哈希学习笔记

哈希学习笔记

时间:2023-02-12 11:13:54浏览次数:43  
标签:hash long 学习 模数 64 笔记 哈希 字符串

板:P3370 【模板】字符串哈希
复杂度:O(n)
用途:将一串字符串映射到一个数


怎么写?

选取一个较小质数 p 选取一个较大质数 mod1
将字符串转换成一个 p 进制在 mod1 定义下的数
常见模数:1e9+7(但很容易被卡)
不太容易被卡的模数:19260817 123456791

写法如下:

image


哈希冲突

根据哈希的写法 我们不难发现 相同的字符串的 hash 值一定相等
但 hash 值相等的字符串一定相同吗? 其实不然

事实上 是有可能存在两个不同字符串转换后的 hash 值相同的情况 我们将其称之为哈希冲突
这里给出结论 若字符串的长度为 \(n\) 则模数若不超过 \(n^2\) 就很容易发生哈希冲突

那么如何避免 hash 冲突呢?

1.unsigned long long

unsigned long long 的数据范围为 \(0-2^{64}\) 当取值大于 \(2^{64}\) 时会自动溢出 相当于是自动对 \(2^{64}\) 取模

缺点:有概率会被丧心病狂的出题人卡

2.双哈希

顾名思义 就是准备两个模数 做两遍哈希

优点:我们认为是无法被 hack 的

缺点:常数巨大 取模和除法运算又很慢 有可能慢到 TLE

3.哈希表

优点:安全

缺点:我不会写 写起来有点麻烦

4.unordered_map

有点:写起来非常方便

缺点:STL...懂得都懂


同时 哈希还支持查询子串的 hash 值
需要 O(n) 的复杂度 O(1) 查询
首先我们要开一个数组 把之前每一步的 ch 记录下来

我们以十进制数为例 观察如何查询中间一段数字的值
如这段:123456789 我们要查询第 3 位至第 7 位 即34567

我们已知每一段前缀的 hash 值 不难发现我们要用到 hash[2] = 12 与 hash[7] = 1234567

然后我们发现 $34567 = 1234567 - 12 * 10^5 $

根据这个式子 我们可以推广出 \(hash[l,r] = ha[r] - ha[l-1] * ch[r-l+1]\)
具体代码如下:

image

标签:hash,long,学习,模数,64,笔记,哈希,字符串
From: https://www.cnblogs.com/Steven24/p/17113332.html

相关文章