哈希表学习
存储结构
开放寻址法
#include <iostream>
#include <cstring>
using i64 = long long;
const int N = 2000003, null = 0x3f3f3f3f;
int h[N];
int find(int x) {
int k = (x % N + N) % N;
while(h[k] != null && h[k] != x) {
k ++;
if(k == N) k = 0;
}
return k;
}
int main() {
// for(int i = 2e6; ; i ++) {
// bool ok = true;
// for(int j = 2; j <= i / j; j ++) {
// if(i % j == 0) {
// ok = false;
// break;
// }
// }
// if(ok) {
// std::cout << i << "\n";
// break;
// }
// }
memset(h, 0x3f, sizeof h);
int n;
std::cin >> n;
while(n --) {
std::string t;
int x;
std::cin >> t >> x;
int k = find(x);
if(t == "I") {
h[k] = x;
} else {
std::cout << ((h[k] != null)?"Yes":"No") << "\n";
}
}
}
拉链法
可以通过一个图来直观的理解。
#include <iostream>
#include <cstring>
using i64 = long long;
const int N = 1e5 + 10, M = 100003;
int mod;
int h[N], e[N], ne[N], idx;
void insert(int x) {
int n = (x % M + M) % M;
ne[idx] = h[n], h[n] = idx, e[idx ++] = x;
}
bool find(int x) {
int n = (x % M + M) % M;
for(int i = h[n]; ~i; i = ne[i]) {
if(e[i] == x) return true;
}
return false;
}
int main() {
memset(h, -1, sizeof h);
// for(int i = 1e5; ; i ++) {
// bool ok = true;
// for(int j = 2; j <= i / j; j ++) {
// if(i % j == 0) {
// ok = false;
// break;
// }
// }
// if(ok) {
// std::cout << i << "\n";
// break;
// }
// }
int n;
std::cin >> n;
while(n --) {
std::string t;
int x;
std::cin >> t >> x;
if(t == "I") {
insert(x);
} else {
std::cout << (find(x)?"Yes":"No") << "\n";
}
}
}
字符串哈希方式
前缀哈希法
思路:将字符串映射到\(p\)进制数(不能将某个字母映射到\(0\)), 另外一般在\(p = 131 或 13331, Q = 2^{64}\)时,能将冲
突更好的减少(\(99.99\% 不存在冲突\))。
\[A \space B \space C \space D \\ →
(1 \space 2 \space 3 \space 4)_p \\
hash[ABCD] = (1 \times p^3 + 2 \times p^2 + 3 \times p^3 + 4 \times p^4) \bmod Q \\
hash[BC] = hash[ABC] - hash[A] \times p^2 \\
→ hash[R] - hash[L] \times p^{R - L + 1}
\]
对于一个字符串的hash值,我们可以通过计算前缀的hash值,来计算区间的hash值。这里取模有一个技巧,如果我们对\(2^{64}\)取模,相当于unsigned long long
的溢出,即可以用unsingned long long
来代替取模。
#include <iostream>
using i64 = long long;
using ui64 = unsigned long long;
const int N = 1e5 + 10, P = 131;
int n, m;
char str[N];
ui64 h[N], p[N];
ui64 get(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];
}
int main() {
std::cin >> n >> m >> (str + 1);
p[0] = 1;
for(int i = 1; i <= n; i ++) {
p[i] = p[i - 1] * P;
h[i] = h[i - 1] * P + str[i];
}
while(m --) {
int l1, r1, l2, r2;
std::cin >> l1 >> r1 >> l2 >> r2;
std::cout << (get(l1, r1) == get(l2, r2)?"Yes":"No") << "\n";
}
}