题目
不使用任何内建的哈希表库设计一个哈希映射(HashMap)。
实现 MyHashMap 类:
MyHashMap() 用空映射初始化对象
void put(int key, int value) 向 HashMap 插入一个键值对 (key, value) 。如果 key 已经存在于映射中,则更新其对应的值 value 。
int get(int key) 返回特定的 key 所映射的 value ;如果映射中不包含 key 的映射,返回 -1 。
void remove(key) 如果映射中存在 key 的映射,则移除 key 和它所对应的 value 。
示例:
输入:
[“MyHashMap”, “put”, “put”, “get”, “get”, “put”, “get”, “remove”, “get”]
[[], [1, 1], [2, 2], [1], [3], [2, 1], [2], [2], [2]]
输出:
[null, null, null, 1, -1, null, 1, null, -1]
解释:
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // myHashMap 现在为 [[1,1]]
myHashMap.put(2, 2); // myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(1); // 返回 1 ,myHashMap 现在为 [[1,1], [2,2]]
myHashMap.get(3); // 返回 -1(未找到),myHashMap 现在为 [[1,1], [2,2]]
myHashMap.put(2, 1); // myHashMap 现在为 [[1,1], [2,1]](更新已有的值)
myHashMap.get(2); // 返回 1 ,myHashMap 现在为 [[1,1], [2,1]]
myHashMap.remove(2); // 删除键为 2 的数据,myHashMap 现在为 [[1,1]]
myHashMap.get(2); // 返回 -1(未找到),myHashMap 现在为 [[1,1]]
提示:
0 <= key, value <= 10^6
最多调用 104 次 put、get 和 remove 方法
分析
这道题目要求自建一个map,最简单的办法就是通过数组实现,key作为数组的下标,value作为数组元素,这种有个问题在于需要给数组做一遍初始化为一个负数(因为map的value也可能是0),初始化一个10^6的数组还是需要一定的时间的,同时空间复杂度也很大,如果一直没有元素插入进来,就会有这个数组一直占着内存
或者换一个思路,减少空间复杂度的思路一定是链表,新增一个元素给他开一个空间,同时为了减少初始化的遍历时间,我们可以把这个数组的长度设置为1000,也无需任何初始化操作,这样后续肯定会有不同的key命中到相同的索引上,为了解决这个问题,我们把数组的元素类型设置成一个链表结点,链表结点的key是map的key,value是map的value,我们通过一个hash函数来把map的key换算到1000以内保证可以在数组中有对应的索引,这样如果我们的hash函数足够的分散的话,就能保证我们的链表也足够分散,put/get/remove函数的时间复杂度也不会太大。当然极端情况下所有的key都命中到一个链表,那这种情况下就需要遍历这个长链表去插入查询删除元素,这样其实也是非常耗时的
public class MyHashMap {
Node[] a;
public class Node{
int key;
int value;
Node next;
Node(int key,int value){
this.key = key;
this.value = value;
this.next = null;
}
}
public MyHashMap(){
a = new Node[1000];
}
public void put(int key,int value) {
int hashKey = getHash(key);
Node head = a[hashKey];
if(head == null) {
a[hashKey] = new Node(key,value);
} else {
Node pre = null;
while(head != null) {
if(head.key ==key) {
head.value = value;
return;
} else {
pre = head;
head = head.next;
}
}
pre.next = new Node(key,value);
}
}
public void remove(int key) {
int hashKey = getHash(key);
Node head = a[hashKey];
if(head != null && head.key ==key) {
a[hashKey] = head.next;
return;
}
Node pre = null;
while(head != null) {
if(head.key == key) {
pre.next = head.next;
return;
} else {
pre = head;
head = head.next;
}
}
}
public int get(int key) {
int hashKey = getHash(key);
Node head = a[hashKey];
while(head != null) {
if(head.key == key) {
return head.value;
} else {
head = head.next;
}
}
return -1;
}
public int getHash(int key) {
int m = Integer.hashCode(key);
return m / 1000;
}
}
public class designHashMap {
public static void main(String[] args) {
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // myHashMap 现在为 [[1,1]]
myHashMap.put(2, 2); // myHashMap 现在为 [[1,1], [2,2]]
System.out.println(myHashMap.get(1)); // 返回 1 ,myHashMap 现在为 [[1,1], [2,2]]
System.out.println(myHashMap.get(3)); // 返回 -1(未找到),myHashMap 现在为 [[1,1], [2,2]]
myHashMap.put(2, 1); // myHashMap 现在为 [[1,1], [2,1]](更新已有的值)
System.out.println(myHashMap.get(2)); // 返回 1 ,myHashMap 现在为 [[1,1], [2,1]]
myHashMap.remove(2); // 删除键为 2 的数据,myHashMap 现在为 [[1,1]]
System.out.println(myHashMap.get(2)); // 返回 -1(未找到),myHashMap 现在为 [[1,1]]
}
}