Design HashSet
Easy · Linked List · Explanation and code example
Bit Manipulation
How it works
We can compress the boolean array approach by using individual bits instead of booleans. Each integer stores 32 bits, so we need only about 31251 integers to cover 1000000+ keys. We use bit operations to set, clear, and check individual bits. This reduces memory usage by a factor of 32 compared to a boolean array.
Steps
- Initialize an integer array of size
31251(since31251 * 32 = 1000032covers all keys). - Define
getMask(key)as1 << (key % 32)to create a bitmask for the key's position within its integer. - For
add(key): Set the bit usingset[key / 32] |= getMask(key). - For
remove(key): If the key exists, toggle the bit usingset[key / 32] ^= getMask(key). - For
contains(key): Returntrueifset[key / 32] & getMask(key)is non-zero.
Complexity
- Time complexity:
O(1)for each function call. - Space complexity:
O(k)
Where
kis the size of the set(31251).
Things to watch for
Adding Duplicate Keys
The add() operation should be idempotent - adding an existing key should have no effect. A common mistake is not checking for duplicates before insertion.
Using XOR for Remove Without Checking Existence
In the bit manipulation approach, using XOR to remove a key that doesn't exist will incorrectly add it instead.
Python code example
class MyHashSet:
def __init__(self):
# key is in the range [0, 1000000]
# 31251 * 32 = 1000032
self.set = [0] * 31251
def add(self, key: int) -> None:
self.set[key // 32] |= self.getMask(key)
def remove(self, key: int) -> None:
if self.contains(key):
self.set[key // 32] ^= self.getMask(key)
def contains(self, key: int) -> bool:
return self.set[key // 32] & self.getMask(key) != 0
def getMask(self, key: int) -> int:
return 1 << (key % 32)
C++ code example
class MyHashSet {
private:
int set[31251];
int getMask(int key) {
return 1 << (key % 32);
}
public:
MyHashSet() {
// key is in the range [0, 1000000]
// 31251 * 32 = 1000032
memset(set, 0, sizeof(set));
}
void add(int key) {
set[key / 32] |= getMask(key);
}
void remove(int key) {
if (contains(key)) {
set[key / 32] ^= getMask(key);
}
}
bool contains(int key) {
return (set[key / 32] & getMask(key)) != 0;
}
};
Source and license
Adapted from NeetCode’s source · MIT license. Node types are supplied by LeetCode where needed.