题目链接
https://leetcode-cn.com/problems/design-hashset/
描述
不使用任何内建的哈希表库设计一个哈希集合
具体地说,你的设计应该包含以下的功能
add(value):向哈希集合中插入一个值。
contains(value) :返回哈希集合中是否存在这个值。
remove(value):将给定值从哈希集合中删除。如果哈希集合中没有这个值,什么也不做。
注意:
所有的值都在 [0, 1000000]的范围内。
操作的总数目在[1, 10000]范围内。
不要使用内建的哈希集合库。
示例
示例:
MyHashSet hashSet = new MyHashSet();
hashSet.add(1);
hashSet.add(2);
hashSet.contains(1); // 返回 true
hashSet.contains(3); // 返回 false (未找到)
hashSet.add(2);
hashSet.contains(2); // 返回 true
hashSet.remove(2);
hashSet.contains(2); // 返回 false (已经被删除)
初始代码模板
class MyHashSet {
/** Initialize your data structure here. */
public MyHashSet() {
}
public void add(int key) {
}
public void remove(int key) {
}
/** Returns true if this set contains the specified element */
public boolean contains(int key) {
}
}
/**
* 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);
*/
代码
根据题目的数据量,可以直接定义一个数组,没有必要用int,因为操作很简单。
虽然这样写能通过测试,但是并没有什么用,纯粹是为了做题而做题。
设计哈希集合,是很考究数据结构能力的一个题目。
class MyHashSet {
private boolean[] hash;
/** Initialize your data structure here. */
public MyHashSet() {
this.hash = new boolean[1000001];
}
public void add(int key) {
hash[key] = true;
}
public void remove(int key) {
hash[key] = false;
}
/** Returns true if this set contains the specified element */
public boolean contains(int key) {
return hash[key];
}
}
/**
* 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);
*/
设计哈希集合,主要考虑哈希函数和冲突的解决方案。详细的说明可以参考官方题解,这里采用链地址法解决冲突:
https://leetcode-cn.com/problems/design-hashset/solution/she-ji-ha-xi-ji-he-by-leetcode/
至于为什么求模运算一般选取质数,是为了减少冲突,具体的可以网上搜一下,我这里并没有特别好的推荐。
可以直接用LInkedList作为链表:
class MyHashSet {
private Bucket[] bucketArray;
private int keyRange;
/** Initialize your data structure here. */
public MyHashSet() {
this.keyRange = 769;
this.bucketArray = new Bucket[this.keyRange];
for (int i = 0; i < this.keyRange; ++i)
this.bucketArray[i] = new Bucket();
}
protected int _hash(int key) {
return (key % this.keyRange);
}
public void add(int key) {
int bucketIndex = this._hash(key);
this.bucketArray[bucketIndex].insert(key);
}
public void remove(int key) {
int bucketIndex = this._hash(key);
this.bucketArray[bucketIndex].delete(key);
}
/** Returns true if this set contains the specified element */
public boolean contains(int key) {
int bucketIndex = this._hash(key);
return this.bucketArray[bucketIndex].exists(key);
}
}
class Bucket {
private LinkedList<Integer> container;
public Bucket() {
container = new LinkedList<Integer>();
}
public void insert(Integer key) {
int index = this.container.indexOf(key);
if (index == -1) {
this.container.addFirst(key);
}
}
public void delete(Integer key) {
this.container.remove(key);
}
public boolean exists(Integer key) {
int index = this.container.indexOf(key);
return (index != -1);
}
}
/**
* 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);
*/
也可以自己定义一个节点类,下面是自己写的,参考个思路就行,不擅长泛型,为了节省空间也没有用傀儡节点:
class MyHashSet {
private Node[] bucketArr;
private int keyRange;
/** Initialize your data structure here. */
public MyHashSet() {
this.keyRange = 769;
this.bucketArr = new Node[this.keyRange];
}
private int countHash(int key) {
return key % this.keyRange;
}
public void add(int key) {
int bucketIndex = this.countHash(key);
Node head = bucketArr[bucketIndex];
//如果此处没有节点,就把节点直接作为头节点
if (head == null) {
bucketArr[bucketIndex] = new Node(key);
} else {
//如果节点已经存在,可以退出方法,不再插入
if (head.val == key) {
return;
}
while (head.next != null) {
if (head.next.val == key) {
return;
}
head = head.next;
}
//不存在则新建一个节点
head.next = new Node(key);
}
}
public void remove(int key) {
int bucketIndex = countHash(key);
Node head = this.bucketArr[bucketIndex];
if (head == null) {
return;
}
if (head.val == key) {
bucketArr[bucketIndex] = head.next;
} else {
while (head.next != null) {
if (head.next.val == key) {
head.next = head.next.next;
return;
}
head = head.next;
}
}
}
/** Returns true if this set contains the specified element */
public boolean contains(int key) {
Node head = bucketArr[countHash(key)];
while (head != null) {
if (head.val == key) {
return true;
}
head = head.next;
}
return false;
}
}
class Node {
int val;
Node next;
Node () {
}
Node(int val) {
this.val = val;
}
}
/**
* 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);
*/
如果为了提升效率,还可以使用二叉搜索树,官方题解里有,但是个人水平有限,留到以后再补充。
如果想优化,可以继续试试平衡二叉搜索树,红黑树~