【PAT】09 哈希表

第九章 哈希表

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. 集合相似度

问题描述

分析

  • 使用多个哈希表存储着多个集合。

  • 对于每次查询的两个集合,可以通过遍历一个集合中的元素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. 朋友数

问题描述

分析

  • 按照题目要求模拟一遍即可。因为最终的输出要求有序,因此可以使用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. 漏掉的数字

问题描述

分析

  • 将所有数据放到哈希表中,然后从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. 危险品装箱

问题描述

分析

  • 对于每个集装箱,遍历所有危险物品对,判断是否该集装箱同时存在危险的物品对即可。

代码

  • 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. 哈希

问题描述

分析

  • 按照题意模拟一遍即可。

代码

  • 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. 期终成绩

问题描述

分析

  • 考虑学生信息的存储,可以使用结构体存储每个学生的信息。然后使用哈希表存储所有学生的信息。

  • 之后对于哈希表中的每个学生,计算其最终的成绩,并判断是否合格,合格的话放到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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值