Design a HashSet without using any built-in hash table libraries.
Implement MyHashSet
class:
void add(key)
Inserts the valuekey
into the HashSet.bool contains(key)
Returns whether the valuekey
exists in the HashSet or not.void remove(key)
Removes the valuekey
in the HashSet. Ifkey
does not exist in the HashSet, do nothing.
Example 1:
Input ["MyHashSet", "add", "add", "contains", "contains", "add", "contains", "remove", "contains"] [[], [1], [2], [1], [3], [2], [2], [2], [2]] Output [null, null, null, true, false, null, true, null, false] Explanation MyHashSet myHashSet = new MyHashSet(); myHashSet.add(1); // set = [1] myHashSet.add(2); // set = [1, 2] myHashSet.contains(1); // return True myHashSet.contains(3); // return False, (not found) myHashSet.add(2); // set = [1, 2] myHashSet.contains(2); // return True myHashSet.remove(2); // set = [1] myHashSet.contains(2); // return False, (already removed)
Constraints:
0 <= key <= 106
- At most
104
calls will be made toadd
,remove
, andcontains
.
设计一个hashset。复习了一下hashtable的basics吧。几个要素:
1. hash function,如果用简单的取%的话最好取prime number
2. capacity,就是这个数组长度
3. load factor,当数组里超过一定数量百分比的index已经被放入了元素,那就需要capacity * 2并进行rehash来把原来数组里的元素重新hash到新的数组
4. collision handling,open addressing和chaining两种方式,一个是沿着数组接着找下一个空的,一个是用一个linkedlist来存hash到同一个index的元素
这题写的时候就用了一个array of LinkedList来存放元素,实现了rehash的功能。还需要记录一个count表示已经放了多少元素,用来判断rehash的条件。每次add的时候先rehash再加。
这里还有一个小坑,被卡了好久。在取array里面一个list的时候,如果取成一个新的变量,然后对这个变量进行修改,其实改不到原来的数组里的那个值,因为它相当于是一份copy of content,not reference。(应该是吧,至少现在试出来是这样)
class MyHashSet {
int capacity = 2;
double loadFactor = 0.75;
List<Integer>[] lists;
int count = 0;
public MyHashSet() {
lists = new LinkedList[capacity];
}
public void add(int key) {
if (contains(key)) {
return;
}
if (count > capacity * loadFactor) {
capacity *= 2;
List<Integer>[] old = lists;
lists = new LinkedList[capacity];
for (List<Integer> list : old) {
if (list != null) {
for (int i : list) {
add(i);
}
}
}
}
if (lists[hash(key)] == null) {
lists[hash(key)] = new LinkedList<>();
}
lists[hash(key)].add(key); // must use lists[hash(key)]
count++;
}
public void remove(int key) {
if (!contains(key)) {
return;
}
List<Integer> list = lists[hash(key)];
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == key) {
list.remove(i);
count--;
}
}
}
public boolean contains(int key) {
List<Integer> list = lists[hash(key)];
if (list != null) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == key) {
return true;
}
}
}
return false;
}
private int hash(int i) {
return i % capacity;
}
}
/**
* Your MyHashSet object will be instantiated and called as such:
* MyHashSet obj = new MyHashSet();
* obj.add(key);
* obj.remove(key);
* boolean param_3 = obj.contains(key);
*/