力扣-705. 设计哈希集合

1.题目

题目地址(705. 设计哈希集合 - 力扣(LeetCode))

https://leetcode.cn/problems/design-hashset/

题目描述

不使用任何内建的哈希表库设计一个哈希集合(HashSet)。

实现 MyHashSet 类:

  • void add(key) 向哈希集合中插入值 key
  • bool contains(key) 返回哈希集合中是否存在这个值 key
  • void remove(key) 将给定值 key 从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。
 

示例:

输入:
["MyHashSet", "add", "add", "contains", "contains", "add", "contains", "remove", "contains"]
[[], [1], [2], [1], [3], [2], [2], [2], [2]]
输出:
[null, null, null, true, false, null, true, null, false]

解释:
MyHashSet myHashSet = new MyHashSet();
myHashSet.add(1);      // set = [1]
myHashSet.add(2);      // set = [1, 2]
myHashSet.contains(1); // 返回 True
myHashSet.contains(3); // 返回 False ,(未找到)
myHashSet.add(2);      // set = [1, 2]
myHashSet.contains(2); // 返回 True
myHashSet.remove(2);   // set = [1]
myHashSet.contains(2); // 返回 False ,(已移除)

 

提示:

  • 0 <= key <= 106
  • 最多调用 104addremovecontains

2.题解

2.1 设计哈希映射

思路

这里主要解释下为何尽可能使用素数作为哈希集合/表的大小
参考:哈希表的大小为何最好是素数
参考:算法分析:哈希表的大小为何是素数

主要是因为很多数列都是间隔固定的周期性数列,存储这些数列时,发生哈希冲突的可能性和我们哈希集合的大小的因子数量成正比
如果待存储的数列间隔恰好是是被取模数的因子大小,那么合数要比素数更容易呈现周期性的取模重复。

代码

  • 语言支持:C++

C++ Code:

class MyHashSet {
private:
    vector<list<int>> data;
    static const int base = 769; // 只有static const 变量才能在类内初始化, 只有static是不可的,需要类外初始化
    static int Hash(int key) { return key % base; }

public:
    MyHashSet() : data(base) {}

    void add(int key) {
        int n = Hash(key);
        for (int num : data[n]) {
            if (num == key)
                return;
        }
        data[n].push_back(key);
    }

    void remove(int key) {
        int n = Hash(key);
        for (auto it = data[n].begin(); it != data[n].end(); it++) {
            if (*it == key) {
                data[n].erase(it);
                return; // 这里要注意,我们如果删除当前迭代器指向的对象后,不能再使用该迭代器, 否则会报 heap-use-after-free 的错误
            }
        }
    }

    bool contains(int key) {
        int n = Hash(key);
        for (int num : data[n]) {
            if (num == key)
                return true;
        }
        return false;
    }
};

/**
 * Your MyHashSet object will be instantiated and called as such:
 * MyHashSet* obj = new MyHashSet();
 * obj->add(key);
 * obj->remove(key);
 * bool param_3 = obj->contains(key);
 */

复杂度分析

令 n 为数组长度。

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)
posted @ 2024-05-03 00:37  DawnTraveler  阅读(7)  评论(0编辑  收藏  举报