Design a HashSet without using any built-in hash table libraries.
To be specific, your design should include these functions:
add(value)
: Insert a value into the HashSet.contains(value)
: Return whether the value exists in the HashSet or not.remove(value)
: Remove a value in the HashSet. If the value does not exist in the HashSet, do nothing.
Example:
MyHashSet hashSet = new MyHashSet(); hashSet.add(1); hashSet.add(2); hashSet.contains(1); // returns true hashSet.contains(3); // returns false (not found) hashSet.add(2); hashSet.contains(2); // returns true hashSet.remove(2); hashSet.contains(2); // returns false (already removed)
Note:
- All values will be in the range of
[0, 1000000]
. - The number of operations will be in the range of
[1, 10000]
. - Please do not use the built-in HashSet library.
這道題讓我們設計HashSet,不能用自帶的哈希表的數據結構,而且要我們主要實現添加,刪除,以及判斷是否存在,這三個函數。我們都知道HashSet最有用的地方就是其能夠在常數的時間內判斷某個元素是否存在,這都得歸功於哈希表的作用。但是現在不讓我們用了,但我們還是得保證其常數級的查找效率,那么就用空間來換時間吧。既然題目中說了數字的范圍不會超過1000000,那么我們就申請這么大空間的數組,這樣對於在HashSet中的數字,我們就將其標記為1,不在或者刪除了的就標記為0,檢測的時候就看其值是否為1即可,參見代碼如下:
解法一:
class MyHashSet { public: /** Initialize your data structure here. */ MyHashSet() { data.resize(1000000, 0); } void add(int key) { data[key] = 1; } void remove(int key) { data[key] = 0; } /** Returns true if this set contains the specified element */ bool contains(int key) { return data[key] == 1; } private: vector<int> data; };
我們可以來適度的優化一下空間復雜度,由於存入HashSet的數字也許不會跨度很大,那么直接就申請長度為1000000的數組可能會有些浪費,那么我們其實可以使用1000個長度為1000的數組來代替,那么就要用個二維數組啦,實際上開始我們只申請了1000個空數組,對於每個要處理的元素,我們首先對1000取余,得到的值就當作哈希值,對應我們申請的那1000個空數組的位置,在加入元素時,一旦計算出了哈希值,我們將對應的空數組resize為長度1000,然后根據哈希值和key/1000來確定具體的加入位置。移除數字一樣的,先計算出哈希值,如果對應的數組不為空的話,找到對應的位置並賦值為0。不過大家也可以看出來,我們在加入元素時會開辟1000的新空間,但是刪除這個元素時,並沒有檢測這1000個位置是否均為0,是的話應該刪除這1000個新空間。但是這樣可能會使得刪除函數變慢一些,參見代碼如下:
解法二:
class MyHashSet { public: /** Initialize your data structure here. */ MyHashSet() { data.resize(1000, vector<int>()); } void add(int key) { int hashKey = key % 1000; if (data[hashKey].empty()) { data[hashKey].resize(1000); } data[hashKey][key / 1000] = 1; } void remove(int key) { int hashKey = key % 1000; if (!data[hashKey].empty()) { data[hashKey][key / 1000] = 0; } } /** Returns true if this set contains the specified element */ bool contains(int key) { int hashKey = key % 1000; return !data[hashKey].empty() && data[hashKey][key / 1000]; } private: vector<vector<int>> data; };
類似題目:
參考資料:
https://leetcode.com/problems/design-hashset/
https://leetcode.com/problems/design-hashset/discuss/185826/C%2B%2B-solution
https://leetcode.com/problems/design-hashset/discuss/193132/Solution-without-boolean-array