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)\)