LeetCode Problem Workspace
Design HashSet
Implement a custom HashSet without built-in libraries using array scanning and hash lookup for efficient membership checks.
5
Topics
5
Code langs
3
Related
Practice Focus
Easy · Array scanning plus hash lookup
Answer-first summary
Implement a custom HashSet without built-in libraries using array scanning and hash lookup for efficient membership checks.
Ace coding interviews with Interview AiBoxInterview AiBox guidance for Array scanning plus hash lookup
To solve Design HashSet, implement a class with add, remove, and contains operations using array-based buckets and a hash function. The key is mapping input keys to bucket indices to manage collisions via linked lists or dynamic arrays. This approach ensures O(1) average insertion and lookup time while handling duplicates and removals efficiently.
Problem Statement
Design a HashSet without relying on any built-in hash table or set libraries. Implement the MyHashSet class with the following methods: add(key), remove(key), and contains(key) to store integer keys efficiently.
Your implementation should handle collisions, prevent duplicates, and support at most 10^4 method calls with keys in the range 0 to 10^6. Optimize operations using array scanning combined with hash lookup to meet time constraints.
Examples
Example 1
Input: See original problem statement.
Output: See original problem statement.
Input ["MyHashSet", "add", "add", "contains", "contains", "add", "contains", "remove", "contains"] [[], [1], [2], [1], [3], [2], [2], [2], [2]] Output [null, null, null, true, false, null, true, null, false]
Explanation MyHashSet myHashSet = new MyHashSet(); myHashSet.add(1); // set = [1] myHashSet.add(2); // set = [1, 2] myHashSet.contains(1); // return True myHashSet.contains(3); // return False, (not found) myHashSet.add(2); // set = [1, 2] myHashSet.contains(2); // return True myHashSet.remove(2); // set = [1] myHashSet.contains(2); // return False, (already removed)
Constraints
- 0 <= key <= 106
- At most 104 calls will be made to add, remove, and contains.
Solution Approach
Choose a bucket structure
Initialize an array of buckets and map each key to a bucket index using a hash function. Use a linked list or dynamic array in each bucket to store actual keys, allowing O(1) average insertion and deletion while scanning the bucket linearly for collisions.
Implement add, remove, and contains
For add, first check if the key exists in the bucket to prevent duplicates, then append if absent. For remove, scan the bucket and delete the key if present. For contains, scan the bucket and return true if the key is found, otherwise return false.
Handle collisions efficiently
When multiple keys map to the same bucket, traverse the linked list or array linearly to check for duplicates and removals. Properly managing collisions ensures consistent performance and prevents overwriting or missing keys.
Complexity Analysis
| Metric | Value |
|---|---|
| Time | Depends on the final approach |
| Space | Depends on the final approach |
Time complexity depends on bucket count and hash distribution: average O(1) for add, remove, and contains if collisions are minimal; worst-case O(n) if all keys hash to one bucket. Space complexity is proportional to the number of buckets plus the total stored keys.
What Interviewers Usually Probe
- They may ask about handling collisions and why a linked list in each bucket works.
- Expect questions on trade-offs between array scanning and hash table performance.
- You might be prompted to explain worst-case scenarios when all keys hash to one bucket.
Common Pitfalls or Variants
Common pitfalls
- Not handling duplicate keys correctly in add operations, causing redundant entries.
- Ignoring collision handling, which can lead to incorrect contains or remove results.
- Choosing too few buckets, increasing linear scanning time and degrading performance.
Follow-up variants
- Implement a HashSet with open addressing instead of linked list buckets.
- Support dynamic resizing of buckets when load factor exceeds a threshold.
- Implement a HashMap variant that stores key-value pairs with similar hashing strategy.
FAQ
What is the best bucket size for Design HashSet to minimize collisions?
A bucket size proportional to the expected number of unique keys (around 10^4) ensures minimal collisions and near O(1) performance.
Can I use built-in set or hash table libraries in this problem?
No, the problem explicitly requires implementing a custom HashSet without any built-in hash table or set structures.
How does the array scanning plus hash lookup pattern work here?
Each key is hashed to a bucket index; scanning within the bucket checks for existence, enabling efficient add, remove, and contains operations.
What happens if multiple keys map to the same bucket?
Collisions are resolved by scanning the bucket’s linked list or array, ensuring each key is stored uniquely without overwriting others.
Is dynamic resizing necessary for this HashSet implementation?
It’s optional for this problem due to key constraints, but resizing can improve performance for larger key ranges or frequent insertions.
Solution
Solution 1: Static Array Implementation
Directly create an array of size $1000001$, initially with each element set to `false`, indicating that the element does not exist in the hash set.
class MyHashSet:
def __init__(self):
self.data = [False] * 1000001
def add(self, key: int) -> None:
self.data[key] = True
def remove(self, key: int) -> None:
self.data[key] = False
def contains(self, key: int) -> bool:
return self.data[key]
# Your MyHashSet object will be instantiated and called as such:
# obj = MyHashSet()
# obj.add(key)
# obj.remove(key)
# param_3 = obj.contains(key)Solution 2: Array of Linked Lists
We can also create an array of size $SIZE=1000$, where each position in the array is a linked list.
class MyHashSet:
def __init__(self):
self.data = [False] * 1000001
def add(self, key: int) -> None:
self.data[key] = True
def remove(self, key: int) -> None:
self.data[key] = False
def contains(self, key: int) -> bool:
return self.data[key]
# Your MyHashSet object will be instantiated and called as such:
# obj = MyHashSet()
# obj.add(key)
# obj.remove(key)
# param_3 = obj.contains(key)Continue Practicing
Continue Topic
array
Practice more edge cases under the same topic.
arrow_forwardauto_awesomeContinue Pattern
Array scanning plus hash lookup
Expand the same solving frame across more problems.
arrow_forwardsignal_cellular_altSame Difficulty Track
Easy
Stay on this level to stabilize interview delivery.
arrow_forward