diff --git a/MyHashMap_DoubleHashing.java b/MyHashMap_DoubleHashing.java new file mode 100644 index 00000000..8a47cf62 --- /dev/null +++ b/MyHashMap_DoubleHashing.java @@ -0,0 +1,80 @@ +// Using double hashing + +// Time Complexity : O(1) +// Space Complexity : O(1) +// Did this code successfully run on Leetcode : Yes +// Any problem you faced while coding this : No + +// Your code here along with comments explaining your approach +// I am using double hashing to handle collisions. +// The hash function is designed to distribute keys evenly across the buckets, reducing the likelihood of collisions. +// When a collision occurs, the second hash function is used to determine the bucket item index, further reducing the +// chance of collisions within the same bucket. +// Also, I am using wrapper class Integer instead of primitive int to handle null values, which is necessary for collision resolution. +// And returing the -1 if key is not found in get method. As int would have default value of 0. + + +class MyHashMap { + + Integer [][] storage; + int buckets; + int bucketItems; + + public MyHashMap() { + this.buckets = 1000; + this.bucketItems = 1000; + this.storage = new Integer[buckets][]; + } + + private int hash1(int key){ + return key % buckets; + } + private int hash2(int key){ + return key / buckets; + } + + // Time Complexity : O(1) + // Space Complexity : O(1) + public void put(int key, int value) { + int bucket = hash1(key); + int bucketItem = hash2(key); + + if(storage[bucket] == null){ + if(bucket == 0){ + storage[bucket] = new Integer[bucketItems + 1]; + }else{ + storage[bucket] = new Integer[bucketItems]; + } + + } + storage[bucket][bucketItem] = value; + } + + // Time Complexity : O(1) + // Space Complexity : O(1) + public int get(int key) { + int bucket = hash1(key); + int bucketItem = hash2(key); + + if(storage[bucket] == null || storage[bucket][bucketItem] == null) return -1; + return storage[bucket][bucketItem]; + } + + // Time Complexity : O(1) + // Space Complexity : O(1) + public void remove(int key) { + int bucket = hash1(key); + int bucketItem = hash2(key); + + if(storage[bucket] == null || storage[bucket][bucketItem] == null) return; + storage[bucket][bucketItem] = null; + } +} + +/** + * Your MyHashMap object will be instantiated and called as such: + * MyHashMap obj = new MyHashMap(); + * obj.put(key,value); + * int param_2 = obj.get(key); + * obj.remove(key); + */ \ No newline at end of file diff --git a/MyHashMap_chaining.java b/MyHashMap_chaining.java new file mode 100644 index 00000000..3e7b2381 --- /dev/null +++ b/MyHashMap_chaining.java @@ -0,0 +1,102 @@ +// Time Complexity : O(1) +// Space Complexity : O(1) +// Did this code successfully run on Leetcode : Yes +// Any problem you faced while coding this : No + + +// Your code here along with comments explaining your approach +// I am using the chaining approach to implement the hashmap. The basic idea is to use an array of linked lists to store key-value pairs. +// The hash function is used to determine the index in the array where the key-value pair should be stored. +// When a collision occurs, the key-value pair is added to the linked list at that index. +// The search operation involves traversing the linked list at the index to find the key-value pair. +// The put operation involves adding a new key-value pair to the linked list at the index, or updating the value if the key already exists. +// The get operation involves searching the linked list at the index for the key and returning the corresponding value. +// The remove operation involves searching the linked list at the index for the key and removing the key-value pair if found. + +class MyHashMap { + private class Node{ + int key, value; + Node next; + Node(int key, int value){ + this.key = key; + this.value = value; + } + } + private Node [] storage; + private int buckets; + public MyHashMap() { + this.buckets = 10000; + this.storage = new Node[buckets]; + } + + // Time Complexity : O(1) + // Space Complexity : O(1) + private int myHashFunction (int key){ + return key % buckets; + } + + // Time Complexity : amortized O(1) + // Space Complexity : O(1) + private Node search(Node head , int key){ + + Node previousNode = head; + Node currentNode = previousNode.next; + + while(currentNode != null && currentNode.key != key){ + previousNode = currentNode; + currentNode = currentNode.next; + } + return previousNode; + + } + + // Time Complexity : amortized O(1) + // Space Complexity : O(1) + + public void put(int key, int value) { + int index = myHashFunction(key); + if(storage[index] == null){ + storage[index] = new Node(-1,-1); + } + Node prev = search(storage[index], key); + if(prev.next == null){ + prev.next = new Node(key, value); + }else{ + prev.next.value = value; + } + } + + // Time Complexity : amortized O(1) + // Space Complexity : O(1) + + public int get(int key) { + int index = myHashFunction(key); + if(storage[index] == null) return -1; + + Node prev = search(storage[index], key); + + if(prev.next == null || prev.next.key != key) return -1; + return prev.next.value; + + } + + // Time Complexity : amortized O(1) + // Space Complexity : O(1) + + public void remove(int key) { + int index = myHashFunction(key); + if(storage[index] == null) return; + Node prev = search(storage[index], key); + if(prev.next == null) return; + prev.next = prev.next.next; + + } +} + +/** + * Your MyHashMap object will be instantiated and called as such: + * MyHashMap obj = new MyHashMap(); + * obj.put(key,value); + * int param_2 = obj.get(key); + * obj.remove(key); + */ \ No newline at end of file diff --git a/QueueUsingStacks.java b/QueueUsingStacks.java new file mode 100644 index 00000000..5473ee52 --- /dev/null +++ b/QueueUsingStacks.java @@ -0,0 +1,65 @@ + +// Did this code successfully run on Leetcode : Yes +// Any problem you faced while coding this : No + +// Your code here along with comments explaining your approach +// The MyQueue class implements a queue using two stacks. The inStack is used for enqueue operations, +// while the outStack is used for dequeue and peek operations. When the outStack is empty, +// elements are transferred from inStack to outStack to maintain the queue order. + +class MyQueue { + Stack inStack; + Stack outStack; + + public MyQueue() { + this.inStack = new Stack<>(); + this.outStack = new Stack<>(); + } + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + public void push(int x) { + inStack.push(x); + } + + /** + * Time Complexity: Amortized O(1), Worst case O(n) + * Space Complexity: O(1) + */ + public int pop() { + peek(); + return outStack.pop(); + } + + /** + * Time Complexity: Amortized O(1), Worst case O(n) + * Space Complexity: O(1) + */ + public int peek() { + if(outStack.isEmpty()){ + while(!inStack.isEmpty()){ + outStack.push(inStack.pop()); + } + } + return outStack.peek(); + } + + /** + * Time Complexity: O(1) + * Space Complexity: O(1) + */ + public boolean empty() { + return inStack.isEmpty() && outStack.isEmpty(); + } +} + +/** + * Your MyQueue object will be instantiated and called as such: + * MyQueue obj = new MyQueue(); + * obj.push(x); + * int param_2 = obj.pop(); + * int param_3 = obj.peek(); + * boolean param_4 = obj.empty(); + */ \ No newline at end of file