Intuition
- Same as
Intuition
- Brute force, this problem may be solved by using two arrays, one for the key, and the other for the value.
- Otherwise, it can be solved by using buckets. Each bucket can hold key, value pairs. And, each bucket is hashed into. If there are 2069 buckets, there is a chance of collision to one of those buckets for every 2069 keys.
- Therefore, this reduces the time complexity since we no longer have to search through one bucket of all the items (like was done in the brute force case).
- Alternatively, you can use a Linked List to avoid having to use .get() and instead changing the elements in place.
Complexity
Complexity
Runtime
- brute force due to having to do a linear search through all keys on each get, insertion, and removal
- when using buckets, due to the hash function giving many buckets of lesser length.
Space
due to having to store the key, value pairs.
Link to original
Code
Linked List
class ListNode:
def __init__(self, key=-1):
self.key = key
self.next = None
class Bucket:
def __init__(self):
self.bucket = ListNode()
def add(self, key: int) -> None:
itr = self.bucket
prev = itr
while itr:
if itr.key == key:
return
prev = itr
itr = itr.next
prev.next = ListNode(key)
def remove(self, key: int) -> None:
itr = self.bucket
while itr:
if itr.key == key:
prev.next = itr.next
itr.next = None
return
prev = itr
itr = itr.next
def contains(self, key: int) -> bool:
itr = self.bucket
while itr:
if itr.key == key:
return True
itr = itr.next
return False
class MyHashSet:
def __init__(self):
self.prime = 2069
self.set = [Bucket() for _ in range(self.prime)]
def add(self, key: int) -> None:
self.set[key % self.prime].add(key)
def remove(self, key: int) -> None:
self.set[key % self.prime].remove(key)
def contains(self, key: int) -> bool:
return self.set[key % self.prime].contains(key)Bucket Array
class Bucket:
def __init__(self):
self.bucket = []
def add(self, key: int) -> None:
for k in self.bucket:
if k == key:
return
self.bucket.append(key)
def remove(self, key: int) -> None:
for i, k in enumerate(self.bucket):
if k == key:
self.bucket.pop(i)
def contains(self, key: int) -> bool:
return key in self.bucket
class MyHashSet:
def __init__(self):
self.prime = 2069
self.set = [Bucket() for _ in range(self.prime)]
def add(self, key: int) -> None:
self.set[key % self.prime].add(key)
def remove(self, key: int) -> None:
self.set[key % self.prime].remove(key)
def contains(self, key: int) -> bool:
return self.set[key % self.prime].contains(key)Brute Force
class MyHashSet:
def __init__(self):
self.set = []
def add(self, key: int) -> None:
if key in self.set:
return
self.set.append(key)
def remove(self, key: int) -> None:
if key in self.set:
self.set.remove(key)
def contains(self, key: int) -> bool:
return key in self.set Cards
START Basic Front: Design Hashset Back: Ammortize cost with buckets instead of one large bucket.
END