1. Problem Summary
You are asked to implement a basic HashMap data structure from scratch without using:
- built-in hash maps
- dictionary-like containers
Your custom HashMap must support three operations:
put(key, value) get(key) remove(key)
Behavior requirements:
put(key, value)- inserts key-value pair
- if key already exists, update its value
get(key)- return the value associated with key
- if key does not exist, return -1
remove(key)- delete the mapping for the key if it exists
Constraints:
- Keys are integers in the range [0, 10^6]
- Operations must run efficiently
2. Key Insights
Direct array is too large
Even though key range is bounded (up to 1,000,000), storing a direct array that large is space-inefficient.
Hashing required for efficiency
We compute:
bucketIndex = key % BUCKET_SIZE
Collisions are unavoidable
Multiple keys may map to the same bucket index.
Use Separate Chaining
Each bucket contains a list (linked list) of key-value pairs.
Search within bucket is linear
But since bucket count is large, average bucket size remains small.
Updating vs inserting
When calling put, we must check if key already exists in that bucket.
3. Approach
Design using array of buckets where each bucket is a linked list
Steps:
- Choose a bucket size (commonly a prime number like 769 or 1009)
- Create an array of bucket lists
- For
put(key, value):- compute bucket index
- iterate bucket list
- if key found → update value
- else → insert (key, value)
- For
get(key):- compute bucket index
- search bucket
- return stored value or -1
- For
remove(key):- compute bucket index
- search bucket
- remove entry if found
This provides acceptable time performance.
4. Time and Space Complexity
Time Complexity (average)
put → O(1) get → O(1) remove → O(1)
Time Complexity (worst case)
O(N) // if all keys land in same bucket
Space Complexity
O(N) // storing all inserted key-value pairs
5. Java Solution
import java.util.*;
class MyHashMap {
private static final int SIZE = 769;
private List<Pair>[] buckets;
private static class Pair {
int key;
int value;
Pair(int key, int value) {
this.key = key;
this.value = value;
}
}
public MyHashMap() {
buckets = new List[SIZE];
for (int i = 0; i < SIZE; i++) {
buckets[i] = new LinkedList<>();
}
}
private int hash(int key) {
return key % SIZE;
}
public void put(int key, int value) {
int index = hash(key);
List<Pair> bucket = buckets[index];
for (Pair pair : bucket) {
if (pair.key == key) {
pair.value = value; // update existing
return;
}
}
bucket.add(new Pair(key, value));
}
public int get(int key) {
int index = hash(key);
List<Pair> bucket = buckets[index];
for (Pair pair : bucket) {
if (pair.key == key) {
return pair.value;
}
}
return -1;
}
public void remove(int key) {
int index = hash(key);
List<Pair> bucket = buckets[index];
Iterator<Pair> iterator = bucket.iterator();
while (iterator.hasNext()) {
Pair pair = iterator.next();
if (pair.key == key) {
iterator.remove();
return;
}
}
}
}
6. Dry Run Examples
Example 1
Operations:
put(1, 1) put(2, 2) get(1) get(3) put(2, 1) get(2) remove(2) get(2)
Step by step:
put(1,1) → store (1,1)
put(2,2) → store (2,2)
get(1) → returns 1
get(3) → returns -1
put(2,1) → update value for key 2
get(2) → returns 1
remove(2) → delete entry
get(2) → returns -1
Example 2
Handling collision:
Suppose bucket size = 5 and keys:
put(3,10) put(8,20) put(13,30)
All map to same index:
3 % 5 = 3 8 % 5 = 3 13 % 5 = 3
Bucket 3 list:
[(3,10), (8,20), (13,30)]
get(8) scans bucket 3 and returns 20
Example 3
Removing non-existent key:
remove(99)
Bucket empty or doesn’t contain key → do nothing
Example 4
Updating existing value:
put(4,5) put(4,9)
After operations:
get(4) = 9
7. Why This Solution Works
- Uses hashing to distribute keys
- Handles collisions with separate chaining
- Maintains O(1) average performance
- Clean separation of concerns:
- hash function
- bucket storage
- key search/update/delete
- Avoids memory explosion from direct indexing
- Matches required API exactly
8. Common Mistakes
- Forgetting to update value when key already exists
- Returning 0 instead of -1 for missing key
- Using array size too small → causes clustering
- Removing while iterating incorrectly (must use iterator)
- Miscomputing hash index for negative keys (not needed here due to constraints)
