寒假打卡第三天——HashTable

一.什么是哈希表呢?

散列表(也叫哈希表),是根据关键码-值而直接进行访问的数据结构。
哈希表的优点:查找数据速度快

二.存储结构:

把一个大的数据映射成一个小的数据
1.拉链法
2.开放寻址法
拉链法:用数组加链表来模拟
开放寻址法:用当前数据大小的两到三倍空间防止溢出模拟
如何写呢?
题目:维护一个集合,支持如下几种操作:

I x,插入一个数 x;
Q x,询问数 x 是否在集合中出现过;
现在要进行 N 次操作,对于每个询问操作输出对应的结果。

输入格式
第一行包含整数 N,表示操作数量。

接下来 N 行,每行包含一个操作指令,操作指令为 I x,Q x 中的一种。

输出格式
对于每个询问指令 Q x,输出一个询问结果,如果 x 在集合中出现过,则输出 Yes,否则输出 No。

每个结果占一行。

数据范围
1≤N≤105
−109≤x≤109
输入样例:
5
I 1
I 2
I 3
Q 2
Q 5
输出样例:
Yes
No
1.拉链法

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 100003;
int n, x;
char op[2];
int h[N], e[N], ne[N], idx = 1;//链表中定义e[],ne[],idx;
void insert(int x) {
  int k = (x % N + N) % N;//为什么要加N,为了防止k是负数,故要先取
  //模再加再取模
	e[idx] = x;//把x插到k号位置的链表中
  ne[idx] = h[k];
  h[k] = idx++;
}
bool query(int x) {
  int k = (x % N + N) % N;//先找到对应k号下标
	for (int i = h[k]; i; i = ne[i]) {//遍历k的链表
    if (e[i] == x) {//如果找到对应的值,返回真
      return true;
    }
  }
 return false;
}
int main() {
  scanf("%d", &n);
  while (n--) {
    scanf("%s%d", op, &x);//为了防止出题人加空格,所以定义用char [2]
    if (op[0] == 'I') {
      insert(x);
    } else {
      if (query(x))
        printf("Yes\n");
      else
        printf("No\n");
    }
  }
  return 0;
}

2.开放寻址法

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 300007, 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() {
  memset(h, 0x3f, sizeof h);//先把所有数据都初始成最大值
  int n;
  cin >> n;
  char op;
  int x;
  while (n--) {
    cin >> op >> x;
    int k = find(x);
    if (op == 'I')
      h[k] = x;
    else {
      if (h[k] != null)
        cout << "Yes\n";
      else
        cout << "No\n";
    }
  }
 return 0;
}

三. 字符串哈希

题目
给定一个长度为n的字符串,再给定m个询问,每个询问包含四个整数l1,r1,l2,r2,请你判断[l1,r1]和[l2,r2]这两个区间所包含的字符串子串是否完全相同。
字符串中只包含大小写英文字母和数字。

输入格式
第一行包含整数n和m,表示字符串长度和询问次数。
第二行包含一个长度为n的字符串,字符串中只包含大小写英文字母和数字。
接下来m行,每行包含四个整数l1,r1,l2,r2,表示一次询问所涉及的两个区间。
注意,字符串的位置从1开始编号。

输出格式
对于每个询问输出一个结果,如果两个字符串子串完全相同则输出“Yes”,否则输出“No”。
每个结果占一行。
输入

8 3

aabbaabb

1 3 5 7

1 3 6 8

1 2 1 2

输出

Yes

No

Yes

#include <iostream>
#include <algorithm>
using namespace std;
const int N = 100010, P = 131; // 这里的P 是经验值 131 ,或者13331
int n,m;
char str[N];
// 这里用unsigned long long 存储就相当于mod 2 ^ 64, 因为超过了会溢出的
ULL h[N], p[N];  // h[]是存储字符串哈希值的 p[] 是存储p次方的 
ULL get(int l, int r)
{
  return h[r] - h[l -1] * p[r - l + 1];   // 区间hash 的公式
}
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数组保存 计算的次方数
    h[i] = h[i-1] * P +str[i];  // 计算字符串的前缀, 后面的是0次 所以直接加上str[i]就行了
  }
 while(m -- )
  {
    int l1, r1, l2, r2;
    scanf("%d%d%d%d", &l1, &r1, &l2, &r2);
    if(get(l1, r1) == get(l2, r2)) cout << "Yes" << endl;
    else cout << "No" << endl;
  }
  return 0}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值