哈希表
拉链法
/*
* Project: 11_哈希表
* File Created:Sunday, January 17th 2021, 2:11:23 pm
* Author: Bug-Free
* Problem:AcWing 840. 模拟散列表 拉链法
*/
#include <cstring>
#include <iostream>
using namespace std;
const int N = 1e5 + 3; // 取大于1e5的第一个质数,取质数冲突的概率最小 可以百度
//* 开一个槽 h
int h[N], e[N], ne[N], idx; //邻接表
void insert(int x) {
// c++中如果是负数 那他取模也是负的 所以 加N 再 %N 就一定是一个正数
int k = (x % N + N) % N;
e[idx] = x;
ne[idx] = h[k];
h[k] = idx++;
}
bool find(int x) {
//用上面同样的 Hash函数 讲x映射到 从 0-1e5 之间的数
int k = (x % N + N) % N;
for (int i = h[k]; i != -1; i = ne[i]) {
if (e[i] == x) {
return true;
}
}
return false;
}
int n;
int main() {
cin >> n;
memset(h, -1, sizeof h); //将槽先清空 空指针一般用 -1 来表示
while (n--) {
string op;
int x;
cin >> op >> x;
if (op == "I") {
insert(x);
} else {
if (find(x)) {
puts("Yes");
} else {
puts("No");
}
}
}
return 0;
}
开放寻址法
#include <iostream>
#include <cstring>
using namespace std;
//开放寻址法一般开 数据范围的 2~3倍
const int N = 200003;//+3是为了让n变为质数 减少冲突的概率
const int null = 0x3f3f3f3f;
// 0x3f3f3f3f的十进制是1061109567,也就是10^9级别的(和0x7fffffff一个数量级),
// 而一般场合下的数据都是小于10^9的,所以它可以作为无穷大使用而不致出现数据大于无穷大的情形。
int h[N];
int find (int x) {
int k = (x % N + N) % N;//映射k的下标
while (h[k] != null && h[k] != x) {
k++;
if (k == N) {//到最后一个位置
k = 0;
}
}
return k;//如果这个位置为空 则返回它的存储位置
}
int main () {
int n;
cin >> n;
memset(h,0x3f, sizeof h);//将数组清空
while (n --) {
string op;
int x;
cin >> op >> x;
if (op == "I") {
h[find(x)] = x;
}
else {
if (h[find(x)] == null) {
puts("No");
}
else {
puts("Yes");
}
}
}
return 0;
}
memset的用法
字符串哈希
详细思路一
对应代码公式:
import sys
n, m = map(int, sys.stdin.readline().split())
P = 131
s = input()
Q = 1 << 64
h = [0] * (len(s) + 10)
p = [0] * (len(s) + 10)
p[0] = 1
s = " " + s
# 根据公式求
def get(l, r):
return (h[r] - h[l - 1] * p[r - l + 1]) % Q
# 初始化
for i in range(1, len(s)):
h[i] = (h[i - 1] * P + ord(s[i])) % Q
p[i] = p[i - 1] * P % Q
while m:
m -= 1
l1, r1, l2, r2 = map(int, input().split())
if get(l1, r1) == get(l2, r2):
print("Yes")
else:
print("No")
代码二:
// 使用场景:判断两个字符串的子串是否相同
#include <iostream>
using namespace std;
typedef unsigned long long ULL; //2^64 自动取模
const int N = 100010, P = 131;//P取131 or 13331经验值 在99%的情况下不会出现冲突
int n, m;
char str[N];
ULL h[N], p[N];
//获取一段字符串
ULL get(int l, int r) {
return h[r] - h[l - 1] * p[r - l + 1];// 左移到对齐
}
int main () {
scanf("%d%d%s", &n, &m, str + 1);
p[0] = 1;
for (int i = 1; i <= n; i ++) {
p[i] = p[i - 1] * P;//构造p进制 用于get函数中的 对齐
h[i] = h[i - 1] * P + str[i];//字符串处理前缀和:加上str[] 表示这个位置上的字母是什么
}
while (m --) {
int l1, r1, l2, r2;
scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
if (get(l1,r1) == get(l2,r2))
puts("Yes");
else
puts("No");
}
return 0;
}