16.字符串哈希 哈希表

Posted fx1998

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了16.字符串哈希 哈希表相关的知识,希望对你有一定的参考价值。

技术图片

 技术图片

 这个方法叫做字符串前缀哈希法- -

先求出来每个前缀的哈希值

技术图片

 问题1:如何来定义某一个前缀的哈希值

把这个字符串看成是一个P进制的数

每一位上的字母的ascii码,就是这一位上的数

技术图片

 最后mod上一个很小的数,就映射到0 ~ Q - 1

这样就可以把一个字符串转换为一个数字

注意事项1:

一般情况下,不能把某个字母映射成0

比如把A映射成0

那A,AA,AAA都是0了。这样就把不同的字符串映射成同样的数字了,错误

注意事项2:

之前的哈希方式是有处理冲突的机制的

这里我们是假定不会有冲突的

技术图片

 从数学结论上看,在P = 131 或13331,Q = 2 ^ 64的情况下

在99.99%的情况下,不会有冲突

至于为啥不会有冲突,这个就好比常见取模数是1000000001,1000000003,1000000007。可以直接记下来

 问题2:这样的哈希方式再配合上前缀哈希,有啥好处

好处就是可以利用前缀哈希,计算出来每一个子串的哈希值。前缀和思想,万物皆可前缀和

技术图片

 [L, R]的哈希值就可以用公式技术图片计算出来

技术图片

 我们直接用unsigned long long来存储所有的h[]

这样就不用对2 ^ 64取模了,溢出就等价于取模

预处理h[]数组直接用

技术图片

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 100010, P = 131;
 4 char s[N];
 5 typedef unsigned long long ULL;
 6 ULL h[N], p[N];
 7 //p数组用来存储p的多少次方
 8 ULL get(int l, int r) {
 9     return h[r] - h[l - 1] * p[r - l + 1];
10 }
11 //哈希值是0 ~ 2 ^ 64 - 1之间的一个数
12 int main() {
13     int n, m;
14     cin >> n >> m >> s + 1;
15     p[0] = 1; //p的0次方等于1
16     for (int i = 1; i <= n; i++) { //从第一个字母开始
17         p[i] = p[i - 1] * P;
18         h[i] = h[i - 1] * P + s[i];
19     }
20     while (m--) {
21         int l1, r1, l2, r2;
22         cin >> l1 >> r1 >> l2 >> r2;
23         if (get(l1, r1) == get(l2, r2)) {
24             cout << "Yes" << endl;
25         } else {
26             cout << "No" << endl;
27         }
28     }
29     return 0;
30 }

 

以上是关于16.字符串哈希 哈希表的主要内容,如果未能解决你的问题,请参考以下文章

构造哈希表/哈希函数

HashMap原理:哈希函数的设计

数据结构哈希表,求大神,急急急

数据结构哈希表,求大神,急急急

数据结构与算法——哈希函数与哈希表等

LeetCode 哈希表 387. 字符串中的第一个唯一字符(计数哈希表,字符串)