拉链法哈希表
#include <iostream>
using namespace std;
/*
维护一个集合,支持如下几种操作:
1." I x ",插入一个数 x ;
2." Q x ",询问数 x 是否在集合中出现过;
现在要进行 N 次操作,对于每个询问操作输出对应的结果
输入格式
第一行包含整数 N ,表示操作数量。
接下来 N 行,每行包含一个操作指令,操作指令为" I x "," Q x "中的一种。
输出格式
对于每个询问指令" Q x ",输出一个询问结果,如果 x 在集合中出现过,则输出" Yes ",否则输出" No "。
每个结果占一行。
数据范围
1 ≤ N ≤ 10^5
-10^9 ≤ x ≤ 10^9
*/
const int N = 100003; // 使用质数,使发生哈希冲突的几率较低
int hs[N], val[N], ne[N], idx;
// 哈希函数,返回哈希值
int hash_func(int x)
{
return (x % N + N) % N; // 负数的模为负数,此操作把负数转为正数
}
// 在哈希表中插入数值x
void insert(int x)
{
int k = hash_func(x); // k为哈希值
// 单链表插入操作
val[idx] = x;
ne[idx] = hs[k];
hs[k] = idx;
idx++;
}
// 查询哈希表中是否存在数值x
bool find(int x)
{
int k = hash_func(x);
for (int i = hs[k]; i != -1; i = ne[i])
{
if (val[i] == x)
{
return true;
}
}
return false;
}
int main()
{
// 初始化哈希表,-1结尾表示没有存储值
memset(hs, -1, sizeof hs);
int n;
cin >> n;
while (n--)
{
char op;
int x;
cin >> op >> x;
if (op == 'I')
{
insert(x);
}
else if (op == 'Q')
{
find(x);
}
}
return 0;
}
开放寻址法哈希表
#include <iostream>
using namespace std;
// 开辟数组的大小一般要题目数值范围的2-3倍,且为质数
const int N = 200003;
// 哈希表中存储的为null表示该位置没有被使用
const int null = 0x3f3f3f3f;
int hs[N];
// 哈希函数
int hash_func(int x)
{
return (x % N + N) % N;
}
// 如果 x 存在,返回x所在位置;如果不存在,返回 x 可以存储的位置
int find(int x)
{
int k = hash_func(x);
// 不考虑删除操作
while (hs[k] != null && hs[k] != x)
{
k++;
// 从表头开始查询可插入位置
// 不考虑哈希表已填满的情况(如果填满且没有x值,将进入死循环)
if (k == N)
{
k = 0;
}
}
// 判断的时候判断 hs[k] 是否等于 null值,即可判断是否存在x
return k;
}
int main()
{
// 初始化,每个字节都存储 0x3f,则每个 int 都存储0x3f3f3f3f
memset(hs, 0x3f, sizeof hs);
int n;
cin >> n;
while (n--)
{
char op;
int x;
cin >> op >> x;
int k = find(x);
if (op == 'I')
{
hs[k] = x;
}
else if (op == 'Q')
{
if (hs[k] == null)
{
cout << "No" << endl;
}
else
{
cout << "Yes" << endl;
}
}
}
return 0;
}
字符串哈希
#include <iostream>
using namespace std;
/*
给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数l1,r1,l2,r2,请你判断 [l1,r1] 和 [l2,r2]这两个区间所包含的字符串子串是否完全相同。
字符串中只包含大小写英文字母和数字。
输入格式
第一行包含整数 n 和 m ,表示字符串长度和询问次数。
第二行包含一个长度为 n 的字符串,字符串中只包含大小写英文字母和数字。
接下来 m 行,每行包含四个整数 l1, r1, l2, r2,表示一次询问所涉及的两个区间。
注意,字符串的位置从1开始编号。
输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出" Yes ",否则输出" No "。
每个结果占一行。
*/
typedef unsigned long long ULL;
const int N = 100010;
const int P = 131; // 表示131进制,还可以取13331,取这两个值可降低哈希冲突的概率
int n, m;
char str[N];
ULL hs[N], p[N]; // p[i]表示 P 的 i 次方为多少,预处理后方便后面处理 区间字符串哈希值
// 字符串最长长度为N,其哈希值会十分庞大,需要将其映射到比较小的数值范围 [0,Q), 即求出的哈希值 模(%) 上 Q(Q 一般取 2^64), 所以定义 unsigned long long类型的哈希数组即可省去 取模(%) 的步骤,溢出即是取模
// 返回 [l,r] 区间字符串的哈希值
ULL get_hs(int l, int r)
{
// 区间字符串哈希值公式
return hs[r] - hs[l - 1] * p[r - l + 1];
}
int main()
{
// 从下标为 1 开始存储
cin >> n >> m >> (str + 1);
p[0] = 1; // P的0次方为1
for (int i = 1; i <= n; i++)
{
p[i] = p[i - 1] * P;
// 计算 [1,i] 字符串的哈希值
hs[i] = hs[i - 1] * P + str[i];
}
// 处理询问
while (m--)
{
int l1, r1, l2, r2;
cin >> l1 >> r1 >> l2 >> r2;
// 字符串哈希基本可以忽视哈希冲突的概率,因此哈希值相同即字符串相同
if (get_hs(l1, r1) == get_hs(l2, r2))
{
cout << "Yes" << endl;
}
else
{
cout << "No" << endl;
}
}
return 0;
}