diff --git a/MinStack.java b/MinStack.java new file mode 100644 index 00000000..2d1d889a --- /dev/null +++ b/MinStack.java @@ -0,0 +1,85 @@ +// Time Complexity : +// push(val) -> O(1) +// pop() -> O(1) +// top() -> O(1) +// getMin() -> O(1) +// +// Space Complexity : +// O(N) where N is the number of elements in the stack +// (We use two stacks: one for values, one for tracking minimums) +// +// Did this code successfully run on Leetcode : +// Yes +// +// Any problem you faced while coding this : +// No major issues. The key idea was to: +// - Keep an extra stack to track the minimum at each level +// - Always push the current minimum along with each value +// - Update the min correctly after pop using the min stack + + +// Your code here along with comments explaining your approach + +import java.util.Stack; + +class MinStack { + + // Main stack to store all values + private Stack mainst; + + // Auxiliary stack to store the minimum value at each level + private Stack minst; + + // Variable to track current minimum + private int min; + + public MinStack() { + this.mainst = new Stack<>(); + this.minst = new Stack<>(); + + // Initialize min with maximum possible value + this.min = Integer.MAX_VALUE; + + // Push initial min so that peek() is always safe + this.minst.push(this.min); + } + + public void push(int val) { + // Update the current minimum + min = Math.min(min, val); + + // Push value into main stack + mainst.push(val); + + // Push the updated minimum into min stack + minst.push(min); + } + + public void pop() { + // Pop from both stacks to keep them in sync + mainst.pop(); + minst.pop(); + + // Update current min to the new top of min stack + min = minst.peek(); + } + + public int top() { + // Return the top of the main stack + return mainst.peek(); + } + + public int getMin() { + // Return the current minimum value + return min; + } +} + +/** + * Your MinStack object will be instantiated and called as such: + * MinStack obj = new MinStack(); + * obj.push(val); + * obj.pop(); + * int param_3 = obj.top(); + * int param_4 = obj.getMin(); + */ diff --git a/MyHashSet.java b/MyHashSet.java new file mode 100644 index 00000000..69f693cb --- /dev/null +++ b/MyHashSet.java @@ -0,0 +1,83 @@ +// Time Complexity : +// add(key) -> Average: O(1), Worst: O(n) (when many keys land in same bucket) +// remove(key) -> Average: O(1), Worst: O(n) +// contains(key) -> Average: O(1), Worst: O(n) +// (n = number of elements in the bucket due to collisions) +// +// Space Complexity : +// O(N + B) where N = total keys stored, B = number of buckets (1000) +// +// Did this code successfully run on Leetcode : +// Yes +// +// Any problem you faced while coding this : +// No major issues. The main thing to be careful about is: +// - Initializing the LinkedList bucket only when needed (lazy init) +// - Removing by value using Integer.valueOf(key) so it doesn't treat key as an index +// - Handling negative keys safely using Math.floorMod + + +// Your code here along with comments explaining your approach + +import java.util.LinkedList; + +class MyHashSet { + // Number of buckets (fixed size). More buckets => fewer collisions on average. + int parentbuckets; + + // Array of buckets; each bucket is a LinkedList to handle collisions (separate chaining). + LinkedList[] storage; + + public MyHashSet() { + // Chosen bucket size (common for this LeetCode problem). + this.parentbuckets = 1000; + + // Create an array of LinkedLists (buckets). Buckets are initialized lazily. + this.storage = new LinkedList[parentbuckets]; + } + + // Primary hash function: maps the key into a valid bucket index [0..parentbuckets-1] + // floorMod ensures negative keys also map correctly. + private int getPrimaryHash(int key) { + return Math.floorMod(key, parentbuckets); + } + + public void add(int key) { + int index = getPrimaryHash(key); + + // Lazy bucket creation (saves memory for unused buckets) + if (storage[index] == null) { + storage[index] = new LinkedList<>(); + } + + // Avoid duplicates: only add if it's not already present + if (!storage[index].contains(key)) { + storage[index].add(key); + } + } + + public void remove(int key) { + int index = getPrimaryHash(key); + + // If bucket exists, remove the key if present + if (storage[index] != null) { + // Integer.valueOf(key) removes the object, not by index + storage[index].remove(Integer.valueOf(key)); + } + } + + public boolean contains(int key) { + int index = getPrimaryHash(key); + + // Key exists if bucket exists and it contains the key + return storage[index] != null && storage[index].contains(key); + } +} + +/** + * Your MyHashSet object will be instantiated and called as such: + * MyHashSet obj = new MyHashSet(); + * obj.add(key); + * obj.remove(key); + * boolean param_3 = obj.contains(key); + */