Design a HashMap without using any built-in hash table libraries.

Implement the MyHashMap class:

Input: operations = ["MyHashMap", "put", "put", "get", "get", "put", "get", "remove", "get"]
values = [[], [1, 1], [2, 2], [1], [3], [2, 1], [2], [2], [2]]
Output: [null, null, null, 1, -1, null, 1, null, -1]
Explanation:
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // The map is now [[1,1]]
myHashMap.put(2, 2); // The map is now [[1,1], [2,2]]
myHashMap.get(1); // return 1, The map is now [[1,1], [2,2]]
myHashMap.get(3); // return -1 (i.e., not found), The map is now [[1,1], [2,2]]
myHashMap.put(2, 1); // The map is now [[1,1], [2,1]] (i.e., update the existing value)
myHashMap.get(2); // return 1, The map is now [[1,1], [2,1]]
myHashMap.remove(2); // remove the mapping for 2, The map is now [[1,1]]
myHashMap.get(2); // return -1 (i.e., not found), The map is now [[1,1]]
Constraints:

Contents

This is similar to Design HashSet solution, in this approach, we will use an array of LinkedLists to store elements, we will initialize the array with some initial size, in below implementation we are initializing array with 10000, and the reason we are initializing array with this size is just to have more distribution of elements instead of skewing many element under same index.

In order to find the index where to insert a given key, we will do a modular operation on the key value with array length, this will ensure that we will never got out of bounds of array. int hashIndex = key % array.length;

Implementation steps:
import java.util.LinkedList; public class MyHashMap { LinkedList<Entry>[] map = new LinkedList[10000]; static class Entry { int key; int value; public Entry(int key, int value) { this.key = key; this.value = value; } } public MyHashMap() { for(int i=0; i<map.length; i++) { map[i] = new LinkedList<>(); } } // If key exists, update the value, otherwise add a new entry public void put(int key, int value) { int hashIndex = key % map.length; LinkedList<Entry> list = map[hashIndex]; for(Entry entry: list) { if(entry.key == key) { entry.value = value; return; } } list.add(new Entry(key, value)); } public int get(int key) { int hashIndex = key % map.length; LinkedList<Entry> list = map[hashIndex]; for(Entry entry: list) { if(entry.key == key) { return entry.value; } } return -1; } public void remove(int key) { int hashIndex = key % map.length; LinkedList<Entry> list = map[hashIndex]; for(Entry entry: list) { if (entry.key == key) { list.remove(entry); return; } } } public static void main(String[] args) { MyHashMap myHashMap = new MyHashMap(); myHashMap.put(1, 1); // The map is now [[1,1]] myHashMap.put(2, 2); // The map is now [[1,1], [2,2]] System.out.println(myHashMap.get(1)); // return 1, The map is now [[1,1], [2,2]] System.out.println(myHashMap.get(3)); // return -1 (i.e., not found), The map is now [[1,1], [2,2]] myHashMap.put(2, 1); // The map is now [[1,1], [2,1]] (i.e., update the existing value) System.out.println(myHashMap.get(2)); // return 1, The map is now [[1,1], [2,1]] myHashMap.remove(2); // remove the mapping for 2, The map is now [[1,1]] System.out.println(myHashMap.get(2)); // return -1 (i.e., not found), The map is now [[1,1]] } }
Complexity Analysis:

Time complexity: All opeeration runs in O(1) time, add operation runs in constant time, since we are looking up element using an index and then adding element to the tail of a LinkedList, both remove and contains also runs in constant average time, when you look at the maximum key as per the problem will be 106 and our array size is 104, so even if some of the numbers are skewed at one index, it is still going to be a constant number.
Space complexity: O(1) since we are storing elements into an array of linked lists.

Above implementations source code can be found at GitHub link for Java code