力扣-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
- 最多调用
104
次add
、remove
和contains
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)\)