├── .gitignore ├── README.md ├── pom.xml └── src └── main └── java └── dev └── milikkan └── grind75 ├── BestTimeToBuyAndSellStock.java ├── BinarySearch.java ├── FirstBadVersion.java ├── FloodFill.java ├── ImplementQueueUsingStacks.java ├── InvertBinaryTree.java ├── LinkedListCycle.java ├── LowestCommonAncestorOfABinarySearchTree.java ├── MergeTwoSortedLists.java ├── RansomNote.java ├── TwoSum.java ├── ValidAnagram.java ├── ValidPalindrome.java ├── ValidParentheses.java └── balancedbinarytree └── Solution.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | !**/src/main/**/target/ 4 | !**/src/test/**/target/ 5 | 6 | ### IntelliJ IDEA ### 7 | .idea/encodings.xml 8 | .idea/vcs.xml 9 | .idea/misc.xml 10 | .idea/modules.xml 11 | .idea/jarRepositories.xml 12 | .idea/compiler.xml 13 | .idea/libraries/ 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### Eclipse ### 19 | .apt_generated 20 | .classpath 21 | .factorypath 22 | .project 23 | .settings 24 | .springBeans 25 | .sts4-cache 26 | 27 | ### NetBeans ### 28 | /nbproject/private/ 29 | /nbbuild/ 30 | /dist/ 31 | /nbdist/ 32 | /.nb-gradle/ 33 | build/ 34 | !**/src/main/**/build/ 35 | !**/src/test/**/build/ 36 | 37 | ### VS Code ### 38 | .vscode/ 39 | 40 | ### Mac OS ### 41 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeetCode - Grind75 Challenge 2 | 3 | This is the repo which contains my solutions to the **Grind75** study plan questions. I am using Java for this round. 4 | 5 | [Grind75](https://www.techinterviewhandbook.org/grind75) is a study plan that contains 75 LeetCode questions in an increasing difficulty order. 6 | 7 | My aim is to solve all the problems in 8 weeks, which is the default plan. (Number of questions and weekly time allocation can be customized but I chose to stick with the default one.) 8 | 9 | ## Main Challenge rules: 10 | 1. Solve at least one question every day. 11 | 2. Finish the plan at most in 8 weeks. 12 | 3. Tweet about your progress daily. 13 | 14 | ### Other rules: 15 | - On the first round, try to solve without taking any hints or looking at other solutions. 16 | - If you cannot come up with an optimized solution, try to do best. You can ignore time constraints in this case as long as all the tests pass. 17 | - If you get stuck on a question (for example trying for more than an hour), don't waste any more time and take a quick hint by looking at the example solutions, then try to solve again. 18 | 19 | ### Questions solve so far 20 | | Day | Date | Question | LeetCode link | My solution | 21 | |---|--------------|-------|---------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------| 22 | | 1 | Nov 7, 2022 |Two Sum| [LeetCode](https://leetcode.com/problems/two-sum) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/d6851fe91c2c5c938604f531827c2aa4fecaea07/src/main/java/dev/milikkan/grind75/TwoSum.java) | 23 | | 2 | Nov 8, 2022 |Valid Parentheses| [LeetCode](https://leetcode.com/problems/valid-parentheses/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/ValidParentheses.java) | 24 | | 3 | Nov 9, 2022 |Merge Two Sorted Lists| [LeetCode](https://leetcode.com/problems/merge-two-sorted-lists/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/MergeTwoSortedLists.java) | 25 | | | |Best Time to Buy and Sell Stock| [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/BestTimeToBuyAndSellStock.java) | 26 | | 4 | Nov 10, 2022 |Valid Palindrome| [LeetCode](https://leetcode.com/problems/valid-palindrome/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/ValidPalindrome.java) | 27 | | | |Invert Binary Tree|[LeetCode](https://leetcode.com/problems/invert-binary-tree/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/InvertBinaryTree.java) | 28 | | 5 | Nov 11, 2022 |Valid Anagram|[LeetCode](https://leetcode.com/problems/valid-anagram/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/ValidAnagram.java) | 29 | | | |Binary Search|[LeetCode](https://leetcode.com/problems/binary-search/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/BinarySearch.java) | 30 | | 6 | Nov 12, 2022 |Flood Fill|[LeetCode](https://leetcode.com/problems/flood-fill/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/FloodFill.java) | 31 | | | |Lowest Common Ancestor of a Binary Search Tree|[LeetCode](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/LowestCommonAncestorOfABinarySearchTree.java) | 32 | | 7 | Nov 13, 2022 |Balanced Binary Tree|[LeetCode](https://leetcode.com/problems/balanced-binary-tree/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/balancedbinarytree/Solution.java) | 33 | | | |Linked List Cycle|[LeetCode](https://leetcode.com/problems/linked-list-cycle/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/LinkedListCycle.java) | 34 | | 8 | Nov 14, 2022 |Implement Queue using Stacks|[LeetCode](https://leetcode.com/problems/implement-queue-using-stacks/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/ImplementQueueUsingStacks.java) | 35 | | 9 | Nov 15, 2022 | First Bad Version|[LeetCode](https://leetcode.com/problems/first-bad-version/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/FirstBadVersion.java) | 36 | | | | Ransom Note|[LeetCode](https://leetcode.com/problems/ransom-note/) | [Java code](https://github.com/milikkan/grind75-leetcode/blob/main/src/main/java/dev/milikkan/grind75/RansomNote.java) | 37 | 38 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | dev.milikkan 8 | grind75 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 17 13 | 17 14 | UTF-8 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/BestTimeToBuyAndSellStock.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ 4 | public class BestTimeToBuyAndSellStock { 5 | // time: O(n) 6 | // space: O(1) 7 | public static int maxProfit(int[] prices) { 8 | int minPrice = 0; 9 | int maxPrice = 0; 10 | int profit; 11 | int maxProfit = 0; 12 | 13 | while (minPrice < prices.length - 1 && maxPrice < prices.length - 1) { 14 | if (prices[maxPrice + 1] < prices[maxPrice] && prices[maxPrice + 1] <= prices[minPrice]) { 15 | maxPrice = maxPrice + 1; 16 | minPrice = maxPrice; 17 | } else { 18 | maxPrice = maxPrice + 1; 19 | profit = prices[maxPrice] - prices[minPrice]; 20 | if (profit > maxProfit) maxProfit = profit; 21 | } 22 | } 23 | return maxProfit; 24 | } 25 | 26 | public static void main(String[] args) { 27 | int[] prices1 = {7, 1, 5, 3, 6, 4}; 28 | System.out.println(maxProfit(prices1)); // 5 29 | 30 | int[] prices2 = {7, 6, 4, 3, 1}; 31 | System.out.println(maxProfit(prices2)); // 0 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/BinarySearch.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/binary-search/ 4 | public class BinarySearch { 5 | // time: O(log n) 6 | // space: O(1) 7 | public static int search(int[] nums, int target) { 8 | int minIndex = 0; 9 | int maxIndex = nums.length - 1; 10 | 11 | while (minIndex <= maxIndex) { 12 | int middleIndex = (maxIndex + minIndex) / 2; 13 | if (nums[middleIndex] == target) { 14 | return middleIndex; 15 | } else if (nums[middleIndex] < target) { 16 | minIndex = middleIndex + 1; 17 | } else { 18 | maxIndex = middleIndex - 1; 19 | } 20 | } 21 | 22 | return -1; 23 | } 24 | 25 | public static void main(String[] args) { 26 | int[] nums1 = {-1, 0, 3, 5, 9, 12, 25, 63}; 27 | int target1 = 25; 28 | 29 | int[] nums2 = {-1, 0, 3, 5, 9, 12}; 30 | int target2 = 2; 31 | 32 | int[] nums3 = {2, 5}; 33 | int target3 = 2; 34 | 35 | int[] nums4 = {1}; 36 | int target4 = 1; 37 | 38 | System.out.println(search(nums1, target1)); // 4 39 | System.out.println(search(nums2, target2)); // -1 40 | System.out.println(search(nums3, target3)); // 0 41 | System.out.println(search(nums4, target4)); // 0 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/FirstBadVersion.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/first-bad-version/ 4 | public class FirstBadVersion { 5 | private int badVersion; 6 | 7 | // time: O(logn) 8 | // space: O(1) 9 | // using Binary Search 10 | public int firstBadVersion(int n) { 11 | if (isBadVersion(1)) return 1; 12 | 13 | long left = 1; 14 | long right = n; 15 | 16 | while (left < right) { 17 | // using long to prevent integer overflow 18 | long middle = (left + right) / 2; 19 | boolean isBad = isBadVersion((int) middle); 20 | 21 | if (isBad) right = middle; 22 | else left = middle; 23 | 24 | if (right - left == 1) return (int) right; 25 | } 26 | return (int) right; 27 | } 28 | 29 | public static void main(String[] args) { 30 | FirstBadVersion fbv = new FirstBadVersion(); 31 | fbv.setBadVersion(4); 32 | System.out.println(fbv.firstBadVersion(5)); // 4 33 | 34 | fbv.setBadVersion(1); 35 | System.out.println(fbv.firstBadVersion(1)); // 1 36 | } 37 | 38 | public void setBadVersion(int version) { 39 | this.badVersion = version; 40 | } 41 | 42 | public boolean isBadVersion(int version) { 43 | return version == this.badVersion; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/FloodFill.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | import java.util.LinkedList; 4 | 5 | // problem link: https://leetcode.com/problems/flood-fill/ 6 | public class FloodFill { 7 | // time: O(n) 8 | // space: O(n) 9 | public static int[][] floodFill(int[][] image, int sr, int sc, int color) { 10 | LinkedList nodes = new LinkedList<>(); 11 | nodes.offer(new Node(sr, sc)); 12 | int initialColor = image[sr][sc]; 13 | if (initialColor == color) return image; 14 | 15 | while (!nodes.isEmpty()) { 16 | Node current = nodes.poll(); 17 | int x = current.x; 18 | int y = current.y; 19 | image[x][y] = color; 20 | 21 | if (x >= 1 && image[x - 1][y] == initialColor) { 22 | nodes.offer(new Node(x - 1, y)); 23 | } 24 | if (y >= 1 && image[x][y - 1] == initialColor) { 25 | nodes.offer(new Node(x, y - 1)); 26 | } 27 | if (y < image[x].length - 1 && image[x][y + 1] == initialColor) { 28 | nodes.offer(new Node(x, y + 1)); 29 | } 30 | if (x < image.length - 1 && image[x + 1][y] == initialColor) { 31 | nodes.offer(new Node(x + 1, y)); 32 | } 33 | } 34 | return image; 35 | } 36 | 37 | public static void main(String[] args) { 38 | int[][] image1 = { 39 | {1, 1, 1}, 40 | {1, 1, 0}, 41 | {1, 0, 1} 42 | }; 43 | int sr1 = 1; 44 | int sc1 = 1; 45 | int color1 = 2; 46 | 47 | int[][] result1 = floodFill(image1, sr1, sc1, color1); 48 | printImage(result1); 49 | 50 | int[][] image2 = { 51 | {0, 0, 0}, 52 | {0, 0, 0} 53 | }; 54 | int sr2 = 0; 55 | int sc2 = 0; 56 | int color2 = 0; 57 | 58 | int[][] result2 = floodFill(image2, sr2, sc2, color2); 59 | printImage(result2); 60 | } 61 | 62 | private static void printImage(int[][] image) { 63 | for (int[] row : image) { 64 | for (int num : row) { 65 | System.out.print(num + " "); 66 | } 67 | System.out.println(); 68 | } 69 | System.out.println("---------"); 70 | } 71 | } 72 | 73 | class Node { 74 | int x; 75 | int y; 76 | 77 | public Node(int x, int y) { 78 | this.x = x; 79 | this.y = y; 80 | } 81 | } 82 | 83 | /* 84 | - create a queue 85 | - offer root node (sr, sc) 86 | - check following 87 | - sr - 1 sc 88 | - sr, sc - 1 89 | - sr, sc + 1 90 | - sr + 1, sc 91 | - if sr = 0 -> dont do sr -1 92 | - if sc = 0 -> dont do sc -1 93 | - if sr = image.len - 1 -> dont do sr 94 | - if sc = image[sr].len -> dont do sc 95 | - if sr, sc != original color -> dont do sr, sc 96 | - else offet the node to the queue 97 | - stop if the queue is empty 98 | */ 99 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/ImplementQueueUsingStacks.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | import java.util.ArrayDeque; 4 | import java.util.Deque; 5 | 6 | // problem link: https://leetcode.com/problems/implement-queue-using-stacks/ 7 | public class ImplementQueueUsingStacks { 8 | public static void main(String[] args) { 9 | MyQueue queue1 = new MyQueue(); 10 | queue1.push(1); 11 | System.out.println(queue1); // [1] 12 | 13 | queue1.push(2); 14 | System.out.println(queue1); // [1, 2] 15 | 16 | System.out.println(queue1.peek()); // 1 17 | System.out.println(queue1); // [1, 2] 18 | 19 | System.out.println(queue1.pop()); // 1 20 | System.out.println(queue1);// [2] 21 | 22 | System.out.println(queue1.empty()); // false 23 | 24 | MyQueue queue2 = new MyQueue(); 25 | System.out.println(queue2.peek()); // null 26 | } 27 | } 28 | 29 | class MyQueue { 30 | private final Deque stackForQueue; 31 | private final Deque stackForSwap; 32 | 33 | public MyQueue() { 34 | stackForQueue = new ArrayDeque<>(); 35 | stackForSwap = new ArrayDeque<>(); 36 | } 37 | 38 | public void push(int x) { 39 | while (!stackForQueue.isEmpty()) { 40 | stackForSwap.push(stackForQueue.pop()); 41 | } 42 | 43 | stackForQueue.push(x); 44 | 45 | while (!stackForSwap.isEmpty()) { 46 | stackForQueue.push(stackForSwap.pop()); 47 | } 48 | } 49 | 50 | public Integer pop() { 51 | return stackForQueue.pop(); 52 | } 53 | 54 | public Integer peek() { 55 | return stackForQueue.peek(); 56 | } 57 | 58 | public boolean empty() { 59 | return stackForQueue.isEmpty(); 60 | } 61 | 62 | @Override 63 | public String toString() { 64 | return stackForQueue.toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/InvertBinaryTree.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | import java.util.LinkedList; 4 | 5 | // problem link: https://leetcode.com/problems/invert-binary-tree/ 6 | public class InvertBinaryTree { 7 | 8 | // time: O(n) 9 | // space: O(n) 10 | // traverse method: BFS 11 | public static TreeNode invertTree(TreeNode root) { 12 | if (root == null) return null; 13 | 14 | LinkedList treeNodes = new LinkedList<>(); 15 | treeNodes.offer(root); 16 | 17 | while (!treeNodes.isEmpty()) { 18 | TreeNode current = treeNodes.poll(); 19 | 20 | TreeNode temp = current.left; 21 | current.left = current.right; 22 | current.right = temp; 23 | 24 | if (current.left != null) treeNodes.offer(current.left); 25 | if (current.right != null) treeNodes.offer(current.right); 26 | } 27 | 28 | return root; 29 | } 30 | 31 | public static void main(String[] args) { 32 | TreeNode tree1 = new TreeNode(2, new TreeNode(1), new TreeNode(3)); 33 | 34 | TreeNode tree2 = new TreeNode(4, 35 | new TreeNode(2, new TreeNode(1), new TreeNode(3)), 36 | new TreeNode(7, new TreeNode(6), new TreeNode(9))); 37 | 38 | TreeNode tree3 = null; 39 | 40 | printTreeBFS(invertTree(tree1)); // 2 3 1 41 | printTreeBFS(invertTree(tree2)); // 4 7 2 9 6 3 1 42 | printTreeBFS(invertTree(tree3)); // - 43 | } 44 | 45 | private static void printTreeBFS(TreeNode root) { 46 | if (root == null) return; 47 | 48 | LinkedList treeQueue = new LinkedList<>(); 49 | treeQueue.offer(root); 50 | 51 | while (!treeQueue.isEmpty()) { 52 | TreeNode current = treeQueue.poll(); 53 | System.out.print(current.val + " "); 54 | 55 | if (current.left != null) treeQueue.offer(current.left); 56 | if (current.right != null) treeQueue.offer(current.right); 57 | } 58 | System.out.println(); 59 | } 60 | } 61 | 62 | class TreeNode { 63 | int val; 64 | TreeNode left; 65 | TreeNode right; 66 | 67 | TreeNode() {} 68 | TreeNode(int val) { this.val = val; } 69 | TreeNode(int val, TreeNode left, TreeNode right) { 70 | this.val = val; 71 | this.left = left; 72 | this.right = right; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/LinkedListCycle.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/linked-list-cycle/ 4 | public class LinkedListCycle { 5 | // time: O(n) 6 | // space: O(1) 7 | // solved using Floyd's Tortoise and Hare Algorithm 8 | public static boolean hasCycle(ListNode head) { 9 | var back = head; 10 | var forward = head; 11 | 12 | while (forward != null && forward.next != null) { 13 | forward = forward.next.next; 14 | back = back.next; 15 | if (back == forward) return true; 16 | } 17 | 18 | return false; 19 | } 20 | 21 | public static void main(String[] args) { 22 | var list1Three = new ListNode(3); 23 | var list1Two = new ListNode(2); 24 | var list1Zero = new ListNode(0); 25 | var list1MinusFour = new ListNode(-4); 26 | 27 | list1Three.next = list1Two; 28 | list1Two.next = list1Zero; 29 | list1Zero.next = list1MinusFour; 30 | list1MinusFour.next = list1Two; 31 | 32 | System.out.println(hasCycle(list1Three)); // true 33 | 34 | var list2One = new ListNode(1); 35 | var list2Two = new ListNode(2); 36 | list2One.next = list2Two; 37 | list2Two.next = list2One; 38 | 39 | System.out.println(hasCycle(list2One)); // true 40 | 41 | var list3One = new ListNode(1); 42 | var list3MinusTwo = new ListNode(-2); 43 | list3One.next = list3MinusTwo; 44 | System.out.println(hasCycle(list3One)); // false 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/LowestCommonAncestorOfABinarySearchTree.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/ 4 | public class LowestCommonAncestorOfABinarySearchTree { 5 | // time: O(logn) 6 | // space: O(logn) 7 | public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { 8 | if (p.val < root.val && q.val < root.val) { 9 | return lowestCommonAncestor(root.left, p, q); 10 | } 11 | 12 | if (p.val > root.val && q.val > root.val) { 13 | return lowestCommonAncestor(root.right, p, q); 14 | } 15 | return root; 16 | } 17 | 18 | public static void main(String[] args) { 19 | TreeNode six = new TreeNode(6); 20 | TreeNode two = new TreeNode(2); 21 | TreeNode eight = new TreeNode(8); 22 | TreeNode zero = new TreeNode(0); 23 | TreeNode four = new TreeNode(4); 24 | TreeNode seven = new TreeNode(7); 25 | TreeNode nine = new TreeNode(9); 26 | TreeNode three = new TreeNode(3); 27 | TreeNode five = new TreeNode(5); 28 | // construct tree1 29 | six.left = two; 30 | six.right = eight; 31 | two.left = zero; 32 | two.right = four; 33 | four.left = three; 34 | four.right = five; 35 | eight.left = seven; 36 | eight.right = nine; 37 | 38 | System.out.println(lowestCommonAncestor(six, two, eight).val); // 6 39 | System.out.println(lowestCommonAncestor(six, two, four).val); // 2 40 | } 41 | } 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/MergeTwoSortedLists.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/merge-two-sorted-lists/ 4 | public class MergeTwoSortedLists { 5 | // time: O(n) 6 | // space: O(n) 7 | public static ListNode mergeTwoLists(ListNode list1, ListNode list2) { 8 | ListNode pointer1= list1; 9 | ListNode pointer2 = list2; 10 | 11 | if (pointer1 == null) return pointer2; 12 | if (pointer2 == null) return pointer1; 13 | 14 | ListNode result = new ListNode(); 15 | ListNode rp = result; 16 | 17 | while (true) { 18 | if (pointer1.val == pointer2.val) { 19 | rp.val = pointer1.val; 20 | rp.next = new ListNode(); 21 | rp = rp.next; 22 | rp.val = pointer2.val; 23 | pointer1 = pointer1.next; 24 | pointer2 = pointer2.next; 25 | } else if (pointer1.val < pointer2.val) { 26 | rp.val = pointer1.val; 27 | pointer1 = pointer1.next; 28 | } else { 29 | rp.val = pointer2.val; 30 | pointer2 = pointer2.next; 31 | } 32 | 33 | if (pointer1 == null) { 34 | if (pointer2 != null) rp.next = pointer2; 35 | break; 36 | } 37 | if (pointer2 == null) { 38 | rp.next = pointer1; 39 | break; 40 | } 41 | 42 | rp.next = new ListNode(); 43 | rp = rp.next; 44 | 45 | } 46 | return result; 47 | } 48 | 49 | public static void main(String[] args) { 50 | ListNode list1 = new ListNode(1, 51 | new ListNode(2, 52 | new ListNode(4))); 53 | 54 | ListNode list2 = new ListNode(1, 55 | new ListNode(3, 56 | new ListNode(4))); 57 | 58 | ListNode list3 = new ListNode(5, 59 | new ListNode(7)); 60 | 61 | ListNode list4 = null; 62 | 63 | ListNode result = mergeTwoLists(list1, list2); 64 | printNodeList(result); // should print 1 2 3 4 65 | 66 | result = mergeTwoLists(list1, list3); 67 | printNodeList(result); // should print 1 2 4 5 7 68 | 69 | result = mergeTwoLists(list3, list4); 70 | printNodeList(result); // should print 5 7 71 | 72 | } 73 | 74 | private static void printNodeList(ListNode list) { 75 | ListNode node = list; 76 | 77 | while (node != null) { 78 | System.out.print(node.val + " "); 79 | node = node.next; 80 | } 81 | System.out.println(); 82 | } 83 | } 84 | 85 | class ListNode { 86 | int val; 87 | ListNode next; 88 | ListNode() {} 89 | ListNode(int val) { this.val = val; } 90 | ListNode(int val, ListNode next) { this.val = val; this.next = next; } 91 | } -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/RansomNote.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // problem link: https://leetcode.com/problems/ransom-note/ 7 | public class RansomNote { 8 | // first solution 9 | // time: O(n) 10 | // space: O(n) 11 | public boolean canConstruct1(String ransomNote, String magazine) { 12 | if (ransomNote.length() > magazine.length()) { 13 | return false; 14 | } 15 | 16 | Map letterCounts = new HashMap<>(); 17 | for (char letter : magazine.toCharArray()) { 18 | letterCounts.compute(letter, (k, v) -> (v == null) ? 1 : v + 1); 19 | } 20 | 21 | for (char letter : ransomNote.toCharArray()) { 22 | if (!letterCounts.containsKey(letter) || letterCounts.get(letter) == 0) { 23 | return false; 24 | } else { 25 | letterCounts.computeIfPresent(letter, (k, v) -> v - 1); 26 | } 27 | } 28 | return true; 29 | } 30 | 31 | // second solution 32 | // time: O(n) 33 | // space: O(1) 34 | public boolean canConstruct2(String ransomNote, String magazine) { 35 | if (ransomNote.length() > magazine.length()) { 36 | return false; 37 | } 38 | 39 | int[] letterCounts = new int[26]; 40 | for (char letter : magazine.toCharArray()) { 41 | letterCounts[letter - 'a'] += 1; 42 | } 43 | 44 | for (char letter : ransomNote.toCharArray()) { 45 | letterCounts[letter - 'a'] -= 1; 46 | if (letterCounts[letter - 'a'] == -1) { 47 | return false; 48 | } 49 | } 50 | return true; 51 | } 52 | 53 | public static void main(String[] args) { 54 | RansomNote ransomNote = new RansomNote(); 55 | System.out.println(ransomNote.canConstruct1("a", "b")); // false 56 | System.out.println(ransomNote.canConstruct1("aa", "ab")); // false 57 | System.out.println(ransomNote.canConstruct1("aa", "aab")); // true 58 | 59 | System.out.println(ransomNote.canConstruct2("a", "b")); // false 60 | System.out.println(ransomNote.canConstruct2("aa", "ab")); // false 61 | System.out.println(ransomNote.canConstruct2("aa", "aab")); // true 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/TwoSum.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | // https://leetcode.com/problems/two-sum/ 7 | public class TwoSum { 8 | // time: O(n) 9 | // space: O(n) 10 | public static int[] twoSum(int[] nums, int target) { 11 | Map found = new HashMap<>(); 12 | 13 | for (int idx = 0; idx < nums.length; idx++) { 14 | int current = nums[idx]; 15 | int lookingFor = target - current; 16 | if (found.containsKey(lookingFor)) { 17 | return new int[]{idx, found.get(lookingFor)}; 18 | } 19 | found.put(current, idx); 20 | } 21 | return new int[0]; 22 | } 23 | 24 | public static void main(String[] args) { 25 | int[] nums1 = {2, 7, 11, 15}; 26 | int target1 = 9; 27 | for (int num : twoSum(nums1, target1)) System.out.print(num + " "); 28 | System.out.println(); 29 | 30 | int[] nums2 = {3, 2, 4}; 31 | int target2 = 6; 32 | for (int num : twoSum(nums2, target2)) System.out.print(num + " "); 33 | System.out.println(); 34 | 35 | int[] nums3 = {3, 3, 3, 2}; 36 | int target3 = 5; 37 | for (int num : twoSum(nums3, target3)) System.out.print(num + " "); 38 | System.out.println(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/ValidAnagram.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/valid-anagram/ 4 | public class ValidAnagram { 5 | // time: O(n) 6 | // space: O(1) 7 | public static boolean isAnagram(String s, String t) { 8 | if (s.length() != t.length()) return false; 9 | 10 | char[] lettersS = new char[26]; 11 | char[] lettersT = new char[26]; 12 | 13 | for (int index = 0; index < s.length(); index++) { 14 | int letterPositionS = s.charAt(index) - 'a'; 15 | lettersS[letterPositionS]++; 16 | 17 | int letterPositionT = t.charAt(index) - 'a'; 18 | lettersT[letterPositionT]++; 19 | } 20 | 21 | for (int i = 0; i <= 25; i++) { 22 | if (lettersS[i] != lettersT[i]) return false; 23 | } 24 | 25 | return true; 26 | } 27 | 28 | public static void main(String[] args) { 29 | String s1 = "anagram"; 30 | String t1 = "nagaram"; 31 | 32 | System.out.println(isAnagram(s1, t1)); // true 33 | 34 | String s2 = "rat"; 35 | String t2 = "car"; 36 | System.out.println(isAnagram(s2, t2)); // false 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/ValidPalindrome.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | // problem link: https://leetcode.com/problems/valid-palindrome/ 4 | public class ValidPalindrome { 5 | // time: O(n) 6 | // space: O(1) 7 | public static boolean isPalindrome(String s) { 8 | int leftIndex = 0; 9 | int rightIndex = s.length() - 1; 10 | 11 | while (leftIndex < rightIndex) { 12 | if (!Character.isLetterOrDigit(s.charAt(leftIndex))) { 13 | leftIndex++; 14 | continue; 15 | } 16 | if (!Character.isLetterOrDigit(s.charAt(rightIndex))) { 17 | rightIndex--; 18 | continue; 19 | } 20 | if (Character.toLowerCase(s.charAt(leftIndex)) != Character.toLowerCase(s.charAt(rightIndex))) { 21 | return false; 22 | } 23 | leftIndex++; 24 | rightIndex--; 25 | } 26 | return true; 27 | } 28 | 29 | public static void main(String[] args) { 30 | String s1 = "A man, a plan, a canal: Panama"; 31 | String s2 = "race a car"; 32 | String s3 = " "; 33 | 34 | System.out.println(isPalindrome(s1)); // true 35 | System.out.println(isPalindrome(s2)); // false 36 | System.out.println(isPalindrome(s3)); // true 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/ValidParentheses.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75; 2 | 3 | import java.util.ArrayDeque; 4 | import java.util.Deque; 5 | import java.util.Map; 6 | 7 | // problem link: https://leetcode.com/problems/valid-parentheses/ 8 | public class ValidParentheses { 9 | // time: O(n) 10 | // space: O(n) 11 | public static boolean isValid(String s) { 12 | Map pairs = Map.of( 13 | ')', '(', 14 | ']', '[', 15 | '}', '{' 16 | ); 17 | 18 | Deque stack = new ArrayDeque<>(); 19 | 20 | for (char ch : s.toCharArray()) { 21 | if (!pairs.containsKey(ch)) { 22 | stack.push(ch); 23 | } else if (!stack.isEmpty() && stack.peek() == pairs.get(ch)) { 24 | stack.pop(); 25 | } else { 26 | return false; 27 | } 28 | } 29 | return stack.isEmpty(); 30 | } 31 | 32 | public static void main(String[] args) { 33 | String s1 = "()"; 34 | System.out.println(isValid(s1)); 35 | 36 | String s2 = "()[]{}"; 37 | System.out.println(isValid(s2)); 38 | 39 | String s3 = "(])"; 40 | System.out.println(isValid(s3)); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/dev/milikkan/grind75/balancedbinarytree/Solution.java: -------------------------------------------------------------------------------- 1 | package dev.milikkan.grind75.balancedbinarytree; 2 | 3 | // problem link: https://leetcode.com/problems/balanced-binary-tree/ 4 | public class Solution { 5 | // time: O(n) 6 | // space: O(n) 7 | public static boolean isBalanced(TreeNode root) { 8 | return traverseDFS(root).isBalanced; 9 | } 10 | 11 | private static NodeInfo traverseDFS(TreeNode root) { 12 | if (root == null) { 13 | return new NodeInfo(true, 0); 14 | } 15 | 16 | NodeInfo left = traverseDFS(root.left); 17 | NodeInfo right = traverseDFS(root.right); 18 | 19 | boolean isBalanced = left.isBalanced && 20 | right.isBalanced && 21 | Math.abs(left.level - right.level) <= 1; 22 | 23 | return new NodeInfo(isBalanced, 1 + Math.max(left.level, right.level)); 24 | } 25 | 26 | public static void main(String[] args) { 27 | var tree1 = new TreeNode(3, 28 | new TreeNode(9), 29 | new TreeNode(20, 30 | new TreeNode(15), 31 | new TreeNode(7)) 32 | ); 33 | 34 | var tree2 = new TreeNode(1, 35 | new TreeNode(2, 36 | new TreeNode(3, 37 | new TreeNode(4), 38 | new TreeNode(4)), 39 | new TreeNode(3)), 40 | new TreeNode(2) 41 | ); 42 | 43 | TreeNode tree3 = null; 44 | 45 | System.out.println(isBalanced(tree1)); // true 46 | System.out.println(isBalanced(tree2)); // false 47 | System.out.println(isBalanced(tree3)); // true 48 | } 49 | } 50 | 51 | class TreeNode { 52 | int val; 53 | TreeNode left; 54 | TreeNode right; 55 | 56 | TreeNode() { 57 | } 58 | 59 | TreeNode(int val) { 60 | this.val = val; 61 | } 62 | 63 | TreeNode(int val, TreeNode left, TreeNode right) { 64 | this.val = val; 65 | this.left = left; 66 | this.right = right; 67 | } 68 | } 69 | 70 | class NodeInfo { 71 | boolean isBalanced; 72 | int level; 73 | 74 | public NodeInfo(boolean isBalanced, int level) { 75 | this.isBalanced = isBalanced; 76 | this.level = level; 77 | } 78 | } --------------------------------------------------------------------------------