【Day2】03.01 哈希表

Day2

03.01.03 练习题目(第 02 天)

1. 0349. 两个数组的交集

1.1 题目大意

描述:给定两个数组 nums1nums2

要求:返回两个数组的交集。重复元素只计算一次。

说明

  • 1 ≤ n u m s 1. l e n g t h , n u m s 2. l e n g t h ≤ 1000 1 \le nums1.length, nums2.length \le 1000 1nums1.length,nums2.length1000
  • 0 ≤ n u m s 1 [ i ] , n u m s 2 [ i ] ≤ 1000 0 \le nums1[i], nums2[i] \le 1000 0nums1[i],nums2[i]1000

示例

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的

我的答案

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> set1;
        unordered_set<int> set2;
        vector<int> ans;
        for(int n : nums1){
            set1.insert(n);
        }
        for(int n : nums2){
            set2.insert(n);
        }
        for(int n: set2){
            if(set1.count(n)){
                ans.push_back(n);
            }
        }
        return ans;
    }
};

其他答案

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int> set1(nums1.begin(), nums1.end()); //赋值方式
        vector<int> ans;
        
        for (int n : nums2) {
            if (set1.erase(n)) { // 巧妙的处理方式,能够被擦除,说明存在
                ans.push_back(n);
            }
        }
        
        return ans;
    }
};
//排序 + 双指针
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> ans;
        sort(nums1.begin(), nums1.end());
        sort(nums2.begin(), nums2.end());

        int i = 0, j = 0;
        while (i < nums1.size() && j < nums2.size()) {
            if (nums1[i] == nums2[j]) {
                if (ans.empty() || ans.back() != nums1[i]) {
                    ans.push_back(nums1[i]);
                } // 这个条件设计很巧妙,去重。
                i++;
                j++;
            } else if (nums1[i] < nums2[j]) {
                i++;
            } else {
                j++;
            }
        }

        return ans;
    }
};

2. 0350. 两个数组的交集 II

2.1 题目大意

描述:给定两个数组 nums1nums2

要求:返回两个数组的交集。可以不考虑输出结果的顺序。

说明

  • 输出结果中,每个元素出现的次数,应该与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。
  • 1 ≤ n u m s 1. l e n g t h , n u m s 2. l e n g t h ≤ 1000 1 \le nums1.length, nums2.length \le 1000 1nums1.length,nums2.length1000
  • 0 ≤ n u m s 1 [ i ] , n u m s 2 [ i ] ≤ 1000 0 \le nums1[i], nums2[i] \le 1000 0nums1[i],nums2[i]1000

示例

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]


输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]

我的答案

//占很多步骤还可以优化
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int>map1;
        unordered_map<int,int>map2;
        vector<int> ans;
        for(int i = 0;i<nums1.size();++i){
            map1[nums1[i]] ++;
        }
        for(int i = 0;i<nums2.size();++i){
            map2[nums2[i]] ++;
        }
        for(auto i : map1){
            if(map1[i.first]&&map2[i.first]){
                int tmp = min(map1[i.first],map2[i.first]);
                while(tmp--){
                    ans.push_back(i.first);
                }

            }
        }
        return ans;
    }
};

其他答案

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int, int> counts;
        vector<int> result;
        
        // 计算nums1中每个数字的出现次数
        for (int num : nums1) {
            counts[num]++;
        }
        
        // 遍历nums2,如果数字在counts中存在,则添加到结果中,并减少counts中的计数
        for (int num : nums2) {
            if (counts[num] > 0) {
                result.push_back(num);
                counts[num]--;//有一个一样,就相当于消掉了。
            }
        }
        
        return result;
    }
};
//排序 + 双指针
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        sort(nums1.begin(), nums1.end());
        sort(nums2.begin(), nums2.end());
        vector<int> result;
        
        int i = 0, j = 0;
        while (i < nums1.size() && j < nums2.size()) {
            if (nums1[i] < nums2[j]) {
                ++i;
            } else if (nums1[i] > nums2[j]) {
                ++j;
            } else {
                result.push_back(nums1[i]);
                ++i;
                ++j;
            }
        }
        
        return result;
    }
};

3. 0706. 设计哈希映射

3.1 题目大意

要求:不使用任何内建的哈希表库设计一个哈希映射(HashMap)。

需要满足以下操作:

  • MyHashMap() 用空映射初始化对象。
  • void put(int key, int value) 向 HashMap 插入一个键值对 (key, value) 。如果 key 已经存在于映射中,则更新其对应的值 value
  • int get(int key) 返回特定的 key 所映射的 value;如果映射中不包含 key 的映射,返回 -1
  • void remove(key) 如果映射中存在 key 的映射,则移除 key 和它所对应的 value

说明

  • 0 ≤ k e y , v a l u e ≤ 1 0 6 0 \le key, value \le 10^6 0key,value106
  • 最多调用 1 0 4 10^4 104putgetremove 方法。

示例

输入:
["MyHashMap", "put", "put", "get", "get", "put", "get", "remove", "get"]
[[], [1, 1], [2, 2], [1], [3], [2, 1], [2], [2], [2]]
输出:
[null, null, null, 1, -1, null, 1, null, -1]

解释:
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // myHashMap 现在为 [[1,1]]
myHashMap.put(2, 2); // myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(1);    // 返回 1 ,myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(3);    // 返回 -1(未找到),myHashMap 现在为 [[1,1], [2,2]]
myHashMap.put(2, 1); // myHashMap 现在为 [[1,1], [2,1]](更新已有的值)
myHashMap.get(2);    // 返回 1 ,myHashMap 现在为 [[1,1], [2,1]]
myHashMap.remove(2); // 删除键为 2 的数据,myHashMap 现在为 [[1,1]]
myHashMap.get(2);    // 返回 -1(未找到),myHashMap 现在为 [[1,1]]

我的答案

class MyHashMap {
    vector<int> map;
    int size = 1000001;
public:
    MyHashMap() {
        map.resize(size,-1);
    }
    
    void put(int key, int value) {
        map[key] = value;
    }
    
    int get(int key) {
        return map[key];
    }
    
    void remove(int key) {
        map[key] = -1;
    }
};

其他答案

//链地址法
#include <list>
#include <vector>

class MyHashMap {
private:
    const int BUCKET_SIZE = 769; // 选择一个合适的桶大小以减少冲突
    vector<list<pair<int, int>>> buckets;

public:
    MyHashMap() {
        buckets.resize(BUCKET_SIZE); // 初始化桶的数量
    }
    
    int hash(int key) {
        return key % BUCKET_SIZE; // 简单的哈希函数
    }
    
    list<pair<int, int>>& getBucket(int key) {
        return buckets[hash(key)]; // 获取键对应的桶
    }
    
    pair<int, int>* findPair(list<pair<int, int>>& bucket, int key) {
        for (auto it = bucket.begin(); it != bucket.end(); ++it) {
            if (it->first == key) {
                return &(*it); // 如果找到了键,返回键值对的指针
            }
        }
        return nullptr; // 如果没有找到键,返回 nullptr
    }
    
    void put(int key, int value) {
        int bucketIndex = hash(key);
        list<pair<int, int>>& bucket = getBucket(key);
        pair<int, int>* pair = findPair(bucket, key);
        if (pair) {
            pair->second = value; // 如果键已经存在,更新值
        } else {
            bucket.push_back(make_pair(key, value)); // 如果键不存在,添加新的键值对
        }
    }
    
    int get(int key) {
        int bucketIndex = hash(key);
        list<pair<int, int>>& bucket = getBucket(key);
        pair<int, int>* pair = findPair(bucket, key);
        return pair ? pair->second : -1; // 如果找到了键,返回值;否则返回 -1
    }
    
    void remove(int key) {
        int bucketIndex = hash(key);
        list<pair<int, int>>& bucket = getBucket(key);
        auto it = bucket.begin();
        while (it != bucket.end()) {
            if (it->first == key) {
                bucket.erase(it); // 如果找到了键,从链表中移除键值对
                return;
            }
            ++it;
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值