706. Design HashMap - Detailed Explanation

Free Coding Questions Catalog
Boost your coding skills with our essential coding questions catalog. Take a step towards a better tech career now!

Problem Statement

Design a HashMap without using any built-in hash table libraries. You need to implement the MyHashMap class with the following functionalities:

  • MyHashMap(): Initializes the object with an empty map.

  • void put(int key, int value): Inserts a (key, value) pair into the HashMap. If the key already exists in the map, update the corresponding value.

  • int get(int key): Returns the value to which the specified key is mapped, or -1 if this map contains no mapping for the key.

  • void remove(int key): Removes the key and its corresponding value if the map contains the mapping for the key.

Example

Input:

["MyHashMap", "put", "put", "get", "get", "put", "get", "remove", "get"]
[[], [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);          // returns 1
myHashMap.get(3);          // returns -1 (not found)
myHashMap.put(2, 1);       // update the existing value: The map becomes [[1,1], [2,1]]
myHashMap.get(2);          // returns 1
myHashMap.remove(2);       // remove the mapping for 2: The map is now [[1,1]]
myHashMap.get(2);          // returns -1 (not found)

Hints

  1. Hash Function and Buckets:
    Use a simple hash function such as key % size to map keys to buckets. Each bucket can be implemented as a list (or linked list) to handle collisions via separate chaining.

  2. Collision Handling:
    When two keys hash to the same index, store both entries in the same bucket. You need to check the bucket for an existing key when performing put, get, or remove operations.

Approach: Using Separate Chaining

Explanation

We can design our HashMap by maintaining an array (or list) of buckets. Each bucket is a list that will store key-value pairs. The main operations are implemented as follows:

  • put(key, value):
    1. Compute the bucket index using the hash function (e.g., index = key % size).
    2. Iterate through the bucket:
      • If the key already exists, update its value.
      • If the key does not exist, append the new (key, value) pair.
  • get(key):
    1. Compute the bucket index.
    2. Search through the bucket for the key.
    3. Return the corresponding value if found; otherwise, return -1.
  • remove(key):
    1. Compute the bucket index.
    2. Find and remove the key-value pair from the bucket if it exists.

Step-by-Step Walkthrough

Consider performing the following operations:

  1. Initialization:
    Create an array of fixed size (e.g., 1000 buckets). Each bucket is initially empty.

  2. put(1, 1):

    • Hash key 1 using 1 % 1000 = 1.
    • Bucket at index 1 is empty; add (1, 1).
  3. put(2, 2):

    • Hash key 2 using 2 % 1000 = 2.
    • Bucket at index 2 is empty; add (2, 2).
  4. get(1):

    • Hash key 1; check bucket index 1.
    • Find (1, 1) and return 1.
  5. put(2, 1):

    • Hash key 2; check bucket index 2.
    • Update the value for key 2 to 1.
  6. remove(2):

    • Hash key 2; check bucket index 2.
    • Remove the key-value pair (2, 1).

Python Code

Python3
Python3

. . . .

Java Code

Java
Java

. . . .

Complexity Analysis

  • Time Complexity:

    • The hash function computation is O(1).
    • In the worst-case scenario (all keys collide into the same bucket), the operations put, get, and remove will be O(n) where n is the number of elements in that bucket.
    • With a good hash function and proper bucket size, average-case operations run in O(1) time.
  • Space Complexity:

    • The space complexity is O(N + M) where N is the number of buckets and M is the number of key-value pairs stored. In our implementation, N is fixed (e.g., 1000), so the space used is essentially O(M).

Common Mistakes and Edge Cases

  • Collision Handling:
    Ensure that when multiple keys hash to the same bucket, you iterate through the bucket to check if the key exists before adding a new key-value pair.

  • Updating vs. Inserting:
    When performing the put operation, do not simply append the new pair without checking for an existing key. This can lead to duplicate keys and incorrect get or remove behavior.

  • Negative Keys:
    If negative keys are allowed, ensure the hash function correctly handles them. In our case, the modulo operation may need adjustment to avoid negative indices.

Alternative Variations

  • Open Addressing:
    Instead of separate chaining, you could implement the HashMap using open addressing techniques such as linear probing or quadratic probing. This would store key-value pairs directly in an array and resolve collisions by finding the next available slot.

  • Dynamic Resizing:
    To maintain efficiency when the number of entries grows, you might consider dynamically resizing the bucket array and rehashing the entries.

TAGS
leetcode
CONTRIBUTOR
Design Gurus Team
-

GET YOUR FREE

Coding Questions Catalog

Design Gurus Newsletter - Latest from our Blog
Boost your coding skills with our essential coding questions catalog.
Take a step towards a better tech career now!
Explore Answers
Related Courses
Grokking the Coding Interview: Patterns for Coding Questions
Grokking the Coding Interview Patterns in Java, Python, JS, C++, C#, and Go. The most comprehensive course with 476 Lessons.
Grokking Modern AI Fundamentals
Master the fundamentals of AI today to lead the tech revolution of tomorrow.
Grokking Data Structures & Algorithms for Coding Interviews
Unlock Coding Interview Success: Dive Deep into Data Structures and Algorithms.
Image
One-Stop Portal For Tech Interviews.
Copyright © 2025 Design Gurus, LLC. All rights reserved.
;