第九章 哈希表
AcWing 1532. 找硬币
问题描述
-
问题链接:AcWing 1532. 找硬币、原题链接
分析
- 从前向后依次遍历每个数
x
,然后判断m-x
是否在哈希表中存在,如果存在说明找到一组和为m
的解,更新答案即可。
代码
- C++
#include <iostream>
#include <unordered_set>
using namespace std;
int n, m;
int main() {
scanf("%d%d", &n, &m);
int v1 = 1e9, v2;
unordered_set<int> S;
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
int y = m - x;
if (S.count(y)) {
S.insert(x);
if (x > y) swap(x, y);
if (x < v1) v1 = x, v2 = y;
}
else S.insert(x);
}
if (v1 != 1e9) printf("%d %d", v1, v2);
else puts("No Solution");
return 0;
}
AcWing 1549. 集合相似度
问题描述
-
问题链接:AcWing 1549. 集合相似度、原题链接
分析
-
使用多个哈希表存储着多个集合。
-
对于每次查询的两个集合,可以通过遍历一个集合中的元素
x
,查看x
是否在另一个集合中存在,从而求出nc
;之后nt
就等于两个集合元素数量之和减去nc
。最后按照题目要求输出即可。
代码
- C++
#include <iostream>
#include <unordered_set>
using namespace std;
const int N = 55;
int n;
unordered_set<int> S[N];
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int m;
scanf("%d", &m);
while (m--) {
int x;
scanf("%d", &x);
S[i].insert(x);
}
}
int k;
scanf("%d", &k);
while (k--) {
int a, b;
scanf("%d%d", &a, &b);
int nc = 0;
for (int x : S[a])
if (S[b].count(x))
nc++;
int nt = S[a].size() + S[b].size() - nc;
printf("%.1lf%%\n", (double)nc / nt * 100);
}
return 0;
}
AcWing 1610. 朋友数
问题描述
-
问题链接:AcWing 1610. 朋友数、原题链接
分析
- 按照题目要求模拟一遍即可。因为最终的输出要求有序,因此可以使用
set
。
代码
- C++
#include <iostream>
#include <set>
using namespace std;
int main() {
int n;
cin >> n;
set<int> S;
while (n--) {
int x;
cin >> x;
int s = 0;
while (x) s += x % 10, x /= 10;
S.insert(s);
}
cout << S.size() << endl;
bool is_first = true;
for (int x : S) {
if (is_first) is_first = false;
else cout << ' ';
cout << x;
}
cout << endl;
return 0;
}
AcWing 1637. 漏掉的数字
问题描述
-
问题链接:AcWing 1637. 漏掉的数字、原题链接
分析
- 将所有数据放到哈希表中,然后从
1
遍历到n+1
,判断数据是否在集合中出现,如果没出现,输出对应的数据,结束程序即可。
代码
- C++
#include <iostream>
#include <unordered_set>
using namespace std;
int main() {
int n;
scanf("%d", &n);
unordered_set<int> S;
for (int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
S.insert(x);
}
for (int i = 1; i <= n + 1; i++)
if (S.count(i) == 0) {
printf("%d\n", i);
break;
}
return 0;
}
AcWing 1642. 危险品装箱
问题描述
-
问题链接:AcWing 1642. 危险品装箱、原题链接
分析
- 对于每个集装箱,遍历所有危险物品对,判断是否该集装箱同时存在危险的物品对即可。
代码
- C++
#include <iostream>
#include <unordered_set>
using namespace std;
const int N = 10010, M = 110;
int n, m;
int a[N], b[N]; // 不相容的物品对
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) scanf("%d%d", &a[i], &b[i]);
for (int i = 0; i < m; i++) {
int k;
scanf("%d", &k);
unordered_set<int> S;
while (k--) {
int x;
scanf("%d", &x);
S.insert(x);
}
bool success = true;
for (int j = 0; j < n; j++)
if (S.count(a[j]) && S.count(b[j])) {
success = false;
break;
}
if (success) puts("Yes");
else puts("No");
}
return 0;
}
AcWing 1564. 哈希
问题描述
-
问题链接:AcWing 1564. 哈希、原题链接
分析
- 按照题意模拟一遍即可。
代码
- C++
#include <iostream>
using namespace std;
const int N = 10010;
int s, n; // 哈希表大小[0~s-1], n:输入数据个数
int h[N];
bool is_prime(int x) {
if (x == 1) return false;
for (int i = 2; i * i <= x; i++)
if (x % i == 0)
return false;
return true;
}
int find(int x) { // 找到x应该放置的下标
int t = x % s;
for (int i = 0; i < s; i++) {
int k = (t + i * i) % s;
if (!h[k]) return k;
}
return -1;
}
int main() {
cin >> s >> n;
while (!is_prime(s)) s++;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
int t = find(x);
if (t == -1) printf("-");
else {
h[t] = x;
printf("%d", t);
}
if (i != n - 1) cout << ' ';
}
cout << endl;
return 0;
}
AcWing 1630. 期终成绩
问题描述
-
问题链接:AcWing 1630. 期终成绩、原题链接
分析
-
考虑学生信息的存储,可以使用结构体存储每个学生的信息。然后使用哈希表存储所有学生的信息。
-
之后对于哈希表中的每个学生,计算其最终的成绩,并判断是否合格,合格的话放到
vector
中,最后排序输出即可。
代码
- C++
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <unordered_map>
#include <cmath>
using namespace std;
struct Student {
string id;
int p, m, f, s; // s为最终成绩
Student() : p(-1), m(-1), f(-1), s(0) {}
void calc() {
if (f >= m) s = f;
else s = round(m * 0.4 + f * 0.6);
}
bool operator< (const Student &t) const {
if (s != t.s) return s > t.s;
return id < t.id;
}
};
int main() {
int p, m, n;
cin >> p >> m >> n;
unordered_map<string, Student> students;
string id;
int x;
for (int i = 0; i < p; i++) {
cin >> id >> x;
students[id].id = id;
students[id].p = x;
}
for (int i = 0; i < m; i++) {
cin >> id >> x;
students[id].id = id;
students[id].m = x;
}
for (int i = 0; i < n; i++) {
cin >> id >> x;
students[id].id = id;
students[id].f = x;
}
vector<Student> res;
for (auto &item : students) {
auto t = item.second;
t.calc();
if (t.p >= 200 && t.s >= 60) res.push_back(t);
}
sort(res.begin(), res.end());
for (auto t : res)
cout << t.id << ' ' << t.p << ' ' << t.m << ' ' << t.f << ' ' << t.s << endl;
return 0;
}
AcWing 1638. 哈希 - 平均查找时间
问题描述
分析
-
本题中需要先将数据插入哈希表中,做法是和AcWing 1564. 哈希一样的。
-
之后需要查询给定元素,我们返回每个元素查询次数,最后取平均输出即可。
代码
- C++
#include <iostream>
using namespace std;
const int N = 10010;
int s, n, m;
int h[N];
bool is_prime(int x) {
if (x == 1) return false;
for (int i = 2; i * i <= x; i++)
if (x % i == 0)
return false;
return true;
}
int find(int x, int &cnt) { // cnt: 查询次数
int t = x % s;
cnt = 1;
for (int i = 0; i < s; i++, cnt++) {
int k = (t + i * i) % s;
if (!h[k] || h[k] == x) return k; // 插入的时候h[k]==x一定不成立,因为所有元素不相同
}
return -1;
}
int main() {
cin >> s >> n >> m;
while (!is_prime(s)) s++;
for (int i = 0; i < n; i++) {
int x, count;
cin >> x;
int t = find(x, count);
if (t == -1) printf("%d cannot be inserted.\n", x);
else h[t] = x;
}
int cnt = 0;
for (int i = 0; i < m; i++) {
int x, count;
cin >> x;
find(x, count);
cnt += count;
}
printf("%.1lf\n", (double)cnt / m);
return 0;
}