diff --git a/design_hashmap.py b/design_hashmap.py new file mode 100644 index 00000000..1415f7e4 --- /dev/null +++ b/design_hashmap.py @@ -0,0 +1,89 @@ +# https://leetcode.com/problems/design-hashmap/ + + +# creating a hashmap to store key, value pair. get_hash method is used to find the bucket for the key and then created a get_prev method to find out the previous pointer of the key which about to insert or remove. Then connecting that pointer with new pair while inserting or next pair after the removed pair + +# creating a class MyHashMap +class MyHashMap: + def __init__(self): + # initialising the bucket and storage + self.bucket = 1000 + self.storage = [None] * self.bucket + + class Nodes: + # initialising the attribute of Nodes class + def __init__(self, key, value): + self.key = key + self.value = value + self.next = None + + # method to find a bucket in a map to store the key and value + def get_hash(self, key) -> int: + return key % self.bucket + + # we are using linkedlist in the bucket to store the key, value pair. prev pointer is useful to connect the nodes while adding and removing the key. this method finds previous node of the given key + def get_prev(self, head, key): + prev = None + curr = head + # we need to find the prev pointer of the given key so we are looping until we find the key + while curr is not None and curr.key != key: + # prev is the node before the newly added/removal key + prev = curr + # curr is the node for new key + curr = curr.next + return prev + + # method to insert the key and value pair + def put(self, key: int, value: int) -> None: + # find the bucket using the hash method + index = self.get_hash(key) + # if there is nothing in the bucket means we are adding for the first time + if self.storage[index] is None: + # denoting first element is (-1,-1) in hashmap because while adding or removing the key link could disrupt so dummy acts as a constant at first location + self.storage[index] = self.Nodes(-1, -1) + # newly provided key value is added next to the node + self.storage[index].next = self.Nodes(key, value) + return + # if the bucket is not empty add the time of insertion find the previous pointer of the current key, value pair + prev = self.get_prev(self.storage[index], key) + # if the next of the previous is none we can directly add key value pair + if prev.next is None: + prev.next = self.Nodes(key, value) + # but if there is existing node then need to update the existing value with the new value and key remain unchanged + else: + prev.next.value = value + + # method to return the value of the key + def get(self, key: int) -> int: + index = self.get_hash(key) + # if the bucket for that key is empty + if self.storage[index] is None: + return -1 + # call the prev method to find the previous pointer of the given key + prev = self.get_prev(self.storage[index], key) + # if the prev is the last node then there nothing at next so return -1 + if prev.next is None: + return -1 + # If prev.next is not None, it points to the node containing the key. + return prev.next.value + + # method to remove the key and it's correspondent element + def remove(self, key: int) -> None: + index= self.get_hash(key) + # if bucket is empty + if self.storage[index] is None: + return -1 + # call the prev method to find the previous pointer of the given key + prev = self.get_prev(self.storage[index], key) + if prev.next is None: + return -1 + # link the next node of previous(that is curr which we want to remove) with the next to next node(that is next of the curr) + prev.next = prev.next.next + + +# Your MyHashMap object will be instantiated and called as such: +obj = MyHashMap() +obj.put(2,200) +print(obj.put(2,200)) +param_2 = obj.get(2) +obj.remove(2) \ No newline at end of file diff --git a/queue_using_stacks.py b/queue_using_stacks.py new file mode 100644 index 00000000..8af5d487 --- /dev/null +++ b/queue_using_stacks.py @@ -0,0 +1,64 @@ +# https://leetcode.com/problems/implement-queue-using-stacks/ + +# As we have to implement FIFO approach we can not use same stack for all operationss. Hence, created two stacks. When we have to apply pop and peek we'll update the second stack and for push we'll update first stack. For checking empty we need to use both stacks + +class MyQueue: + + def __init__(self): + # defining empty list becuase we are pushing elements in in_stack and poping and peeking from out_stack + self.in_stack = [] + self.out_stack = [] + + + # method to append the element to the back of the queue + def push(self, x: int) -> None: + # appending an element into the stack + self.in_stack.append(x) + + def pop(self) -> int: + # if both stacks are empty it returns -1 (empty meethod declared in block 4) + if self.empty(): + return -1 + # else call the peek method which returns first element in the list (peek method declared in block 3) + self.peek() + # once we get the first element pop it + return self.out_stack.pop() + + + def peek(self) -> int: + # proceed if there are elements to look at in the in_stack and out_stack + if not self.empty(): + # this condition searches if the out_stack is empty + if not self.out_stack: + # to get the elements from in_stack to out_stack one by one use while loop + while self.in_stack: + # append the popped element from in_stack into the out_stack + self.out_stack.append(self.in_stack.pop()) + # show the last element from the out_stack (which is the first element of the in_stack) + return self.out_stack[-1] + # if there is nothing in both list return None + return None + + + def empty(self) -> bool: + # return True if both stacks are empty else return False + return not self.in_stack and not self.out_stack + + +# Your MyQueue object will be instantiated and called as such: +# obj = MyQueue() +# obj.push(2) +# obj.push(3) +# obj.push(4) +# param_2 = obj.pop() +# print(param_2) +# param_5 = obj.pop() +# print(param_5) +# param_3 = obj.peek() +# print("peek", param_3) +# param_6 = obj.pop() +# print(param_6) +# param_3 = obj.peek() +# print("peek", param_3) +# param_4 = obj.empty() +# print(param_4)