diff --git a/README.md b/README.md
index 989a3224..33b68334 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@ The repo consists of solutions to numerous problems using different data structu
contains solutions to HackerRank problems which I have solved so far and questions from Cracking the Coding Interview
Book _(6th Edition)_.
-You can also refer to my [Java Notes](http://java.ramswaroop.me) for a quick refresh on the Java concepts.
+You can also refer to my [Java Notes](http://blog.rampatra.com/category/java) for a quick refresh on the Java concepts or if you want a break from coding then can read about my [interview experiences](https://blog.rampatra.com/category/interview/) at various companies. Lastly, feel free to connect with me on [Twitter](https://twitter.com/ram__patra) for any queries or concerns. All the best!
## Contents
@@ -50,3 +50,7 @@ IntelliJ IDEA 2018.1.4 (Ultimate Edition)
MacBook Pro
2.5 GHz Intel Core i7
16 GB 1600 MHz DDR3
+
+---
+
+_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/rampatra_). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentifyapp.com), [FaceScreen](https://facescreenapp.com/), [ToDoBar](https://todobarapp.com/), [SimpleFill](https://simplefillapp.com/), and [Apps.Deals](https://www.apps.deals)._
diff --git a/pom.xml b/pom.xml
index 43d083ac..4db680c0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -49,16 +49,16 @@
- * See {@link com.rampatra.trees.LeastCommonAncestorInBT} for a simpler version. + * See {@link com.rampatra.trees.LeastCommonAncestorInBT} for a better answer. * * @param root * @param a diff --git a/src/main/java/com/leetcode/arrays/BuySellStocks.java b/src/main/java/com/leetcode/arrays/BuySellStocks.java index d94c3296..4d4ba02b 100644 --- a/src/main/java/com/leetcode/arrays/BuySellStocks.java +++ b/src/main/java/com/leetcode/arrays/BuySellStocks.java @@ -2,7 +2,27 @@ /** * Level: Easy - * Problem: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ + * Link: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ + * Description: + * Say you have an array for which the ith element is the price of a given stock on day i. + * + * If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), + * design an algorithm to find the maximum profit. + * + * Note that you cannot sell a stock before you buy one. + * + * Example 1: + * + * Input: [7,1,5,3,6,4] + * Output: 5 + * Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. + * Not 7-1 = 6, as selling price needs to be larger than buying price. + * + * Example 2: + * + * Input: [7,6,4,3,1] + * Output: 0 + * Explanation: In this case, no transaction is done, i.e. max profit = 0. * * @author rampatra * @since 2019-04-23 diff --git a/src/main/java/com/leetcode/arrays/BuySellStocksII.java b/src/main/java/com/leetcode/arrays/BuySellStocksII.java index 47966b48..d215246e 100644 --- a/src/main/java/com/leetcode/arrays/BuySellStocksII.java +++ b/src/main/java/com/leetcode/arrays/BuySellStocksII.java @@ -2,8 +2,8 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ - * Problem Description: + * Link: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ + * Description: * Say you have an array for which the ith element is the price of a given stock on day i. *
* Design an algorithm to find the maximum profit. You may complete as many transactions as you diff --git a/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java b/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java index 36e8a491..916499ac 100644 --- a/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java +++ b/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java @@ -1,7 +1,8 @@ package com.leetcode.arrays; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Level: Easy diff --git a/src/main/java/com/leetcode/arrays/FindTheCelebrity.java b/src/main/java/com/leetcode/arrays/FindTheCelebrity.java new file mode 100644 index 00000000..1b15d996 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/FindTheCelebrity.java @@ -0,0 +1,105 @@ +package com.leetcode.arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/find-the-celebrity/ + * Problem Description: + * Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. + * The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them. + * + * Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do + * is to ask questions like: "Hi, A. Do you know B?" to get information of whether A knows B. You need to find out the + * celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense). + * + * You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a + * function int findCelebrity(n). There will be exactly one celebrity if he/she is in the party. Return the celebrity's + * label if there is a celebrity in the party. If there is no celebrity, return -1. + * + * Example 1: + * + * Input: graph = [ + * [1,1,0], + * [0,1,0], + * [1,1,1] + * ] + * Output: 1 + * Explanation: There are three persons labeled with 0, 1 and 2. graph[i][j] = 1 means person i knows person j, otherwise + * graph[i][j] = 0 means person i does not know person j. The celebrity is the person labeled as 1 because both 0 and 2 + * know him but 1 does not know anybody. + * + * + * Example 2: + * + * Input: graph = [ + * [1,0,1], + * [1,1,0], + * [0,1,1] + * ] + * Output: -1 + * Explanation: There is no celebrity. + * + * + * Note: The directed graph is represented as an adjacency matrix, which is an n x n matrix where a[i][j] = 1 means + * person i knows person j while a[i][j] = 0 means the contrary. Remember that you won't have direct access to the + * adjacency matrix. + * + * @author rampatra + * @since 2019-08-04 + */ +public class FindTheCelebrity { + + private int[][] knowsMatrix; + + FindTheCelebrity(int[][] knowsMatrix) { + this.knowsMatrix = knowsMatrix; + } + + public boolean knows(int a, int b) { + return knowsMatrix[a][b] == 1; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * Runtime: 6 ms. + * + * @param n + * @return + */ + public int findCelebrity(int n) { + int celebrityIndex = 0; + + for (int i = 1; i < n; i++) { + // if a person doesn't know another person then he maybe a celebrity + if (!knows(i, celebrityIndex)) { + celebrityIndex = i; + } + } + + for (int i = 0; i < n; i++) { + // verify whether the celebrity only knows himself and all other people know the celebrity + if ((knows(celebrityIndex, i) && i != celebrityIndex) || !knows(i, celebrityIndex)) { + return -1; + } + } + + return celebrityIndex; + } + + public static void main(String[] args) { + FindTheCelebrity findTheCelebrity = new FindTheCelebrity(new int[][]{ + {1, 1, 0}, + {0, 1, 0}, + {1, 1, 1}}); + + assertEquals(1, findTheCelebrity.findCelebrity(3)); + + findTheCelebrity = new FindTheCelebrity(new int[][]{ + {1, 0}, + {0, 1}}); + + assertEquals(-1, findTheCelebrity.findCelebrity(2)); + } +} diff --git a/src/main/java/com/leetcode/arrays/MergeSortedArray.java b/src/main/java/com/leetcode/arrays/MergeSortedArray.java index 09cd730d..975db8ec 100644 --- a/src/main/java/com/leetcode/arrays/MergeSortedArray.java +++ b/src/main/java/com/leetcode/arrays/MergeSortedArray.java @@ -4,7 +4,20 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/merge-sorted-array/ + * Link: https://leetcode.com/problems/merge-sorted-array/ + * Description: + * Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. + * + * Note: + * The number of elements initialized in nums1 and nums2 are m and n respectively. + * You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold + * additional elements from nums2. + * + * Example: + * Input: + * nums1 = [1,2,3,0,0,0], m = 3 + * nums2 = [2,5,6], n = 3 + * Output: [1,2,2,3,5,6] * * @author rampatra * @since 2019-04-26 diff --git a/src/main/java/com/leetcode/arrays/NumberOfIslands.java b/src/main/java/com/leetcode/arrays/NumberOfIslands.java new file mode 100644 index 00000000..04ac6831 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/NumberOfIslands.java @@ -0,0 +1,107 @@ +package com.leetcode.arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/number-of-islands/ + * Description: + * Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water + * and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid + * are all surrounded by water. + *
+ * Example 1: + * Input: + * 11110 + * 11010 + * 11000 + * 00000 + * Output: 1 + *
+ * Example 2: + * Input: + * 11000 + * 11000 + * 00100 + * 00011 + * Output: 3 + * + * @author rampatra + * @since 2019-08-07 + */ +public class NumberOfIslands { + + /** + * The idea is simple and straightforward. Once we encounter land ('1' in grid) we drown the island or change the + * neighboring '1's to '0's. Therefore, the number of '1's we encounter, we can say that we have that many islands. + *
+ * Time Complexity: O(n) + * Space Complexity: O(n) + * Runtime: 1 ms. + * + * @param grid + * @return + */ + public static int numIslands(char[][] grid) { + int count = 0; + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '1') { + drownTheIsland(grid, i, j); + count++; + } + } + } + + return count; + } + + private static void drownTheIsland(char[][] grid, int i, int j) { + if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') { + return; + } + + grid[i][j] = '0'; + + drownTheIsland(grid, i, j + 1); + drownTheIsland(grid, i, j - 1); + drownTheIsland(grid, i + 1, j); + drownTheIsland(grid, i - 1, j); + } + + public static void main(String[] args) { + assertEquals(1, numIslands(new char[][]{ + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '0', '0'} + })); + + assertEquals(2, numIslands(new char[][]{ + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '1', '0'} + })); + + assertEquals(1, numIslands(new char[][]{ + {'1', '1', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '1', '1', '1', '1'} + })); + + assertEquals(1, numIslands(new char[][]{ + {'1'} + })); + + assertEquals(0, numIslands(new char[][]{ + {'0'} + })); + + assertEquals(0, numIslands(new char[][]{ + {} + })); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/RotateArray.java b/src/main/java/com/leetcode/arrays/RotateArray.java index e4f6de33..91475160 100644 --- a/src/main/java/com/leetcode/arrays/RotateArray.java +++ b/src/main/java/com/leetcode/arrays/RotateArray.java @@ -4,7 +4,28 @@ /** * Level: Easy - * Problem: https://leetcode.com/problems/rotate-array/ + * Link: https://leetcode.com/problems/rotate-array/ + * Description: + * Given an array, rotate the array to the right by k steps, where k is non-negative. + * + * Example 1: + * Input: [1,2,3,4,5,6,7] and k = 3 + * Output: [5,6,7,1,2,3,4] + * Explanation: + * rotate 1 steps to the right: [7,1,2,3,4,5,6] + * rotate 2 steps to the right: [6,7,1,2,3,4,5] + * rotate 3 steps to the right: [5,6,7,1,2,3,4] + * + * Example 2: + * Input: [-1,-100,3,99] and k = 2 + * Output: [3,99,-1,-100] + * Explanation: + * rotate 1 steps to the right: [99,-1,-100,3] + * rotate 2 steps to the right: [3,99,-1,-100] + * + * Note: + * Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem. + * Could you do it in-place with O(1) extra space? * * @author rampatra * @since 2019-04-20 diff --git a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java new file mode 100644 index 00000000..5cd0c821 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java @@ -0,0 +1,71 @@ +package com.leetcode.arrays; + +import com.leetcode.hashtables.ShortestWordDistanceII; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/shortest-word-distance/ + * Problem Description: + * Given a list of words and two words word1 and word2, return the shortest distance between these two words in the + * list of words. + * + * Example 1: + * Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + * Given word1 = "coding", word2 = "practice", return 3. + * Given word1 = "makes", word2 = "coding", return 1. + * + * Note: You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. + * + * Lastly, for a more complex variant, see {@link ShortestWordDistanceII}. + * + * @author rampatra + * @since 2019-07-31 + */ +public class ShortestWordDistance { + + /** + * Time Complexity: + * Space Complexity: + * Runtime: 1 ms. + * + * @param words + * @param word1 + * @param word2 + * @return + */ + public static int findShortestDistance(String[] words, String word1, String word2) { + int indexWord1 = -1; + int indexWord2 = -1; + int minDistance = Integer.MAX_VALUE; + + for (int i = 0; i < words.length; i++) { + if (words[i].equals(word1)) { + indexWord1 = i; + } else if (words[i].equals(word2)) { + indexWord2 = i; + } + if (indexWord1 != -1 && indexWord2 != -1) { + minDistance = Math.min(minDistance, Math.abs(indexWord1 - indexWord2)); + } + } + + return minDistance; + } + + public static void main(String[] args) { + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "practice", "coding")); + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "coding", "practice")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "coding")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "perfect")); + assertEquals(0, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "perfect", "perfect")); + assertEquals(0, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "makes")); + } +} diff --git a/src/main/java/com/leetcode/arrays/ShortestWordDistanceIII.java b/src/main/java/com/leetcode/arrays/ShortestWordDistanceIII.java new file mode 100644 index 00000000..0d404633 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/ShortestWordDistanceIII.java @@ -0,0 +1,80 @@ +package com.leetcode.arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/shortest-word-distance-iii/ + * Problem Description: + * This is a follow-up problem of {@link ShortestWordDistance}. The only difference is that now word1 could be the + * same as word2. + *
+ * Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list. + * word1 and word2 may be the same and they represent two individual words in the list. + *
+ * For example, + * Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + * Given word1 = “makes”, word2 = “coding”, return 1. + * Given word1 = "makes", word2 = "makes", return 3. + *
+ * Note: You may assume word1 and word2 are both in the list. If they are same then it's guaranteed that there are + * two occurrences of the same. + * + * @author rampatra + * @since 2019-07-31 + */ +public class ShortestWordDistanceIII { + + /** + * Time Complexity: + * Space Complexity: + * TODO + * + * @param words + * @param word1 + * @param word2 + * @return + */ + public static int findShortestDistance(String[] words, String word1, String word2) { + int indexWord1 = -1; + int indexWord2 = -1; + int minDistance = Integer.MAX_VALUE; + + for (int i = 0; i < words.length; i++) { + if (words[i].equals(word1)) { + // if both words are same and the first index is already set then do nothing + if (word1.equals(word2) && indexWord1 != -1) { + + } else { + indexWord1 = i; + } + } + if (words[i].equals(word2)) { + // if both words are same and i is same as first index then it implies its the + // first occurrence, skip and continue look for the second occurrence + if (word1.equals(word2) && i == indexWord1) { + continue; + } + indexWord2 = i; + } + if (indexWord1 != -1 && indexWord2 != -1) { + minDistance = Math.min(minDistance, Math.abs(indexWord1 - indexWord2)); + } + } + + return minDistance; + } + + public static void main(String[] args) { + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "makes")); + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "coding", "practice")); + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "practice", "coding")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "coding")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "perfect")); + } +} diff --git a/src/main/java/com/leetcode/arrays/SparseMatrixMultiplication.java b/src/main/java/com/leetcode/arrays/SparseMatrixMultiplication.java new file mode 100644 index 00000000..78c884e4 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/SparseMatrixMultiplication.java @@ -0,0 +1,87 @@ +package com.leetcode.arrays; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/sparse-matrix-multiplication/ + * Description: + * Given two sparse matrices A and B, return the result of AB. + * + * You may assume that A's column number is equal to B's row number. + * + * Example: + * + * Input: + * + * A = [ + * [ 1, 0, 0], + * [-1, 0, 3] + * ] + * + * B = [ + * [ 7, 0, 0 ], + * [ 0, 0, 0 ], + * [ 0, 0, 1 ] + * ] + * + * Output: + * + * | 1 0 0 | | 7 0 0 | | 7 0 0 | + * AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 | + * | 0 0 1 | + * + * @author rampatra + * @since 2019-08-09 + */ +public class SparseMatrixMultiplication { + + /** + * Time Complexity: O(Arow * Acol * Bcol) + * Space Complexity: O(Arow * Bcol) + * + * @param A + * @param B + * @return + */ + public static int[][] multiply(int[][] A, int[][] B) { + int[][] AB = new int[A.length][B[0].length]; + + for (int Bcol = 0; Bcol < B[0].length; Bcol++) { + for (int Arow = 0; Arow < A.length; Arow++) { + int sum = 0; + for (int Acol = 0; Acol < A[0].length; Acol++) { + sum += A[Arow][Acol] * B[Acol][Bcol]; + } + AB[Arow][Bcol] = sum; + } + } + + return AB; + } + + public static void main(String[] args) { + assertEquals(Arrays.deepToString(new int[][]{ + {7, 0, 0}, + {-7, 0, 3} + }), Arrays.deepToString(multiply(new int[][]{ + {1, 0, 0}, + {-1, 0, 3} + }, new int[][]{ + {7, 0, 0}, + {0, 0, 0}, + {0, 0, 1} + }))); + + assertEquals(Arrays.deepToString(new int[][]{ + {0} + }), Arrays.deepToString(multiply(new int[][]{ + {0, 1} + }, new int[][]{ + {1}, + {0} + }))); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java b/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java new file mode 100644 index 00000000..cdbfb0c5 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java @@ -0,0 +1,117 @@ +package com.leetcode.arrays; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/valid-triangle-number/ + * Problem Description: + * Given an array consists of non-negative integers, your task is to count the number of triplets chosen from the array + * that can make triangles if we take them as side lengths of a triangle. + *
+ * Example 1: + * Input: [2,2,3,4] + * Output: 3 + * Explanation: + * Valid combinations are: + * 2,3,4 (using the first 2) + * 2,3,4 (using the second 2) + * 2,2,3 + *
+ * Note: + * - The length of the given array won't exceed 1000. + * - The integers in the given array are in the range of [0, 1000]. + * - Triangle Property: Sum of any 2 sides must be greater than the 3rd side. + * + * @author rampatra + * @since 2019-08-07 + */ +public class ValidTriangleNumber { + + /** + * Time complexity : O(n^2 log n). In worst case, the inner loop will take n log n (binary search applied n times). + * Space complexity : O(log n). Sorting takes O(log n) space. + * Runtime: 13 ms. + * + * @param nums + * @return + */ + public static int triangleNumberUsingBinarySearch(int[] nums) { + int noOfTriangles = 0; + + Arrays.sort(nums); + + for (int i = 0; i < nums.length - 2; i++) { + int k = i + 2; + for (int j = i + 1; j < nums.length - 1; j++) { + k = binarySearch(nums, k, nums.length - 1, nums[i] + nums[j]); + if (k - j - 1 > 0) { + noOfTriangles += k - j - 1; + } + } + } + + return noOfTriangles; + } + + private static int binarySearch(int[] nums, int low, int high, int num) { + while (low <= high) { + int mid = (low + high) / 2; + if (nums[mid] < num) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return low; + } + + /** + * The concept is simple. For each pair (i,j), find the value of k such that nums[i] + nums[j] > nums[k] (as per + * triangle property). Once we find k then we can form k- j - 1 triangles. + * + * Time Complexity: O(n^2) Loop of k and j will be executed O(n^2) times in total, because, we do + * not reinitialize the value of k for a new value of j chosen(for the same i). Thus, the complexity + * will be O(n^2 + n^2) = O(n^2). + * Space Complexity: O(log n). Sorting takes O(log n) space. + * Runtime: 5 ms. + * + * @param nums + * @return + */ + public static int triangleNumber(int[] nums) { + int noOfTriangles = 0; + Arrays.sort(nums); + + for (int i = 0; i < nums.length - 2; i++) { + int k = i + 2; + for (int j = i + 1; j < nums.length - 1; j++) { + while (k < nums.length && nums[i] + nums[j] > nums[k]) { + k++; + } + if (k - j - 1 > 0) { + noOfTriangles += k - j - 1; + } + } + } + + return noOfTriangles; + } + + public static void main(String[] args) { + assertEquals(0, triangleNumberUsingBinarySearch(new int[]{})); + assertEquals(0, triangleNumberUsingBinarySearch(new int[]{1})); + assertEquals(3, triangleNumberUsingBinarySearch(new int[]{2, 2, 3, 4})); + assertEquals(0, triangleNumberUsingBinarySearch(new int[]{0, 1, 0, 1})); + assertEquals(7, triangleNumberUsingBinarySearch(new int[]{1, 2, 3, 4, 5, 6})); + + assertEquals(0, triangleNumber(new int[]{})); + assertEquals(0, triangleNumber(new int[]{1})); + assertEquals(3, triangleNumber(new int[]{2, 2, 3, 4})); + assertEquals(0, triangleNumber(new int[]{0, 1, 0, 1})); + assertEquals(7, triangleNumber(new int[]{1, 2, 3, 4, 5, 6})); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java b/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java new file mode 100644 index 00000000..3591c50e --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java @@ -0,0 +1,85 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/powx-n/ + * Description: + * Implement pow(x, n), which calculates x raised to the power n (x^n). + *
+ * Example 1: + * Input: 2.00000, 10 + * Output: 1024.00000 + *
+ * Example 2: + * Input: 2.10000, 3 + * Output: 9.26100 + *
+ * Example 3: + * Input: 2.00000, -2 + * Output: 0.25000 + * Explanation: 2^-2 = 1/22 = 1/4 = 0.25 + *
+ * Note: + * -100.0 < x < 100.0 + * n is a 32-bit signed integer, within the range [−231, 231 − 1] + * + * @author rampatra + * @since 2019-08-19 + */ +public class PowXN { + + /** + * In this approach we iterate n times and keep multiplying x with x. + * Runtime: Time limit exceeded. + * + * @param x + * @param n + * @return + */ + public static double myPowNaive(double x, int n) { + if (n == 0) { + return 1; + } + double res = x; + int absN = Math.abs(n); + for (int i = 1; i < absN; i++) { + res *= x; + } + return n < 0 ? 1 / res : res; + } + + + /** + * In this approach, we iterate log n times. We omit half of n each time. When n is odd, we store whatever product + * we have calculated so far in the final result. + *
+ * Runtime: 1 ms. + * + * @param x + * @param n + * @return + */ + public static double myPow(double x, int n) { + double res = 1; + long absN = Math.abs((long) n); // used a long so that `absN / 2` doesn't overflow + + while (absN > 0) { + if (absN % 2 == 1) res *= x; // store whatever we have calculated so far in the final result + x *= x; + absN /= 2; + } + return n < 0 ? 1 / res : res; + } + + public static void main(String[] args) { + assertEquals(1024.0, myPowNaive(2.0, 10)); + assertEquals(0.25, myPowNaive(2.0, -2)); + assertEquals(0.0, myPowNaive(0.00001, 2147483647)); + + assertEquals(1024.0, myPow(2.0, 10)); + assertEquals(0.25, myPow(2.0, -2)); + assertEquals(0.0, myPow(0.00001, 2147483647)); + } +} diff --git a/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java b/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java new file mode 100644 index 00000000..2f13214a --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java @@ -0,0 +1,64 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Link: https://leetcode.com/problems/search-insert-position/ + * Description: + * Given a sorted array and a target value, return the index if the target is found. If not, return the index where it + * would be if it were inserted in order. + *
+ * You may assume no duplicates in the array. + *
+ * Example 1: + * Input: [1,3,5,6], 5 + * Output: 2 + *
+ * Example 2: + * Input: [1,3,5,6], 2 + * Output: 1 + *
+ * Example 3: + * Input: [1,3,5,6], 7 + * Output: 4 + *
+ * Example 4: + * Input: [1,3,5,6], 0 + * Output: 0 + *
+ * Similar question: {@link SmallestLetterGreaterThanTarget}. + * + * @author rampatra + * @since 2019-08-19 + */ +public class SearchInsertPosition { + + /** + * Runtime: 0 ms. + * + * @param nums + * @param target + * @return + */ + public static int searchInsert(int[] nums, int target) { + int low = 0; + int high = nums.length - 1; + while (low <= high) { + int mid = low + (high - low) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] < target) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return low; + } + + public static void main(String[] args) { + assertEquals(2, searchInsert(new int[]{1, 2}, 3)); + assertEquals(1, searchInsert(new int[]{1, 3, 5, 6}, 2)); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/binarysearch/SmallestLetterGreaterThanTarget.java b/src/main/java/com/leetcode/arrays/binarysearch/SmallestLetterGreaterThanTarget.java new file mode 100644 index 00000000..e44dc339 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/SmallestLetterGreaterThanTarget.java @@ -0,0 +1,87 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Link: https://leetcode.com/problems/find-smallest-letter-greater-than-target/ + * Description: + * Given a list of sorted characters letters containing only lowercase letters, and given a target letter target, find + * the smallest element in the list that is larger than the given target. + * + * Letters also wrap around. For example, if the target is target = 'z' and letters = ['a', 'b'], the answer is 'a'. + * + * Examples: + * + * Input: + * letters = ["c", "f", "j"] + * target = "a" + * Output: "c" + * + * Input: + * letters = ["c", "f", "j"] + * target = "c" + * Output: "f" + * + * Input: + * letters = ["c", "f", "j"] + * target = "d" + * Output: "f" + * + * Input: + * letters = ["c", "f", "j"] + * target = "g" + * Output: "j" + * + * Input: + * letters = ["c", "f", "j"] + * target = "j" + * Output: "c" + * + * Input: + * letters = ["c", "f", "j"] + * target = "k" + * Output: "c" + * + * Note: + * - letters has a length in range [2, 10000]. + * - letters consists of lowercase letters, and contains at least 2 unique letters. + * - target is a lowercase letter. + * + * @author rampatra + * @since 2019-08-19 + */ +public class SmallestLetterGreaterThanTarget { + + /** + * Runtime: 0 ms. + * + * @param letters + * @param target + * @return + */ + public static char nextGreatestLetter(char[] letters, char target) { + int low = 0, hi = letters.length - 1; + while (low <= hi) { + int mid = low + (hi - low) / 2; + if (letters[mid] <= target) { + low = mid + 1; + } else { + hi = mid - 1; + } + } + return letters[low % letters.length]; + } + + public static void main(String[] args) { + assertEquals('a', nextGreatestLetter(new char[]{'a'}, 'z')); + assertEquals('b', nextGreatestLetter(new char[]{'a', 'b'}, 'a')); + assertEquals('b', nextGreatestLetter(new char[]{'a', 'b', 'c'}, 'a')); + assertEquals('a', nextGreatestLetter(new char[]{'a', 'b', 'c'}, 'z')); + assertEquals('c', nextGreatestLetter(new char[]{'c', 'f', 'j'}, 'a')); + assertEquals('f', nextGreatestLetter(new char[]{'c', 'f', 'j'}, 'c')); + assertEquals('f', nextGreatestLetter(new char[]{'c', 'f', 'j'}, 'd')); + assertEquals('b', nextGreatestLetter(new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}, 'a')); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/binarysearch/SqrtX.java b/src/main/java/com/leetcode/arrays/binarysearch/SqrtX.java new file mode 100644 index 00000000..0dde1308 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/SqrtX.java @@ -0,0 +1,62 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Link: https://leetcode.com/problems/sqrtx/ + * Description: + * Implement int sqrt(int x). + * + * Compute and return the square root of x, where x is guaranteed to be a non-negative integer. + * + * Since the return type is an integer, the decimal digits are truncated and only the integer part + * of the result is returned. + * + * Example 1: + * Input: 4 + * Output: 2 + * + * Example 2: + * Input: 8 + * Output: 2 + * Explanation: The square root of 8 is 2.82842..., and since + * the decimal part is truncated, 2 is returned. + * + * @author rampatra + * @since 2019-08-19 + */ +public class SqrtX { + + /** + * Runtime: 1 ms. + * + * @param x + * @return + */ + public static int mySqrt(int x) { + if (x == 0 || x == 1) { + return x; + } + long low = 1; + long high = x / 2; + + while (low <= high) { + long mid = low + (high - low) / 2; + if (mid * mid == x) { + return (int) mid; + } else if (mid * mid < x) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return (int) high; + } + + public static void main(String[] args) { + assertEquals(2, mySqrt(8)); + assertEquals(3, mySqrt(9)); + assertEquals(46339, mySqrt(2147395599)); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/design/AllOne.java b/src/main/java/com/leetcode/design/AllOne.java new file mode 100644 index 00000000..51f771d7 --- /dev/null +++ b/src/main/java/com/leetcode/design/AllOne.java @@ -0,0 +1,125 @@ +package com.leetcode.design; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/all-oone-data-structure/ + * Description: + * Implement a data structure supporting the following operations: + * Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a non-empty + * string. + * Dec(Key) - If Key's value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If + * the key does not exist, this function does nothing. Key is guaranteed to be a non-empty string. + * GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string "". + * GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string "". + *
+ * Challenge: Perform all these in O(1) time complexity.
+ *
+ * @author rampatra
+ * @since 2019-08-11
+ */
+public class AllOne {
+
+
+
+ Map
+ * Example 1:
+ * Input: [2,3,-2,4]
+ * Output: 6
+ * Explanation: [2,3] has the largest product 6.
+ *
+ * Example 2:
+ * Input: [-2,0,-1]
+ * Output: 0
+ * Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
+ *
+ * @author rampatra
+ * @since 2019-08-18
+ */
+public class MaximumProductSubArray {
+
+ /**
+ * The approach is similar to {@link MaximumSubArray} where we update maxUntilIndex only if multiplying the current
+ * number to the product of of all numbers until index produces a larger product and if not make maxUntilIndex the
+ * current number. The only twist here is that we keep two such variables, one for max and one for min, and that's
+ * because the product of two negatives gives us a positive number.
+ *
+ * Runtime: 1 ms.
+ *
+ * @param nums
+ * @return
+ */
+ public static int maxProduct(int[] nums) {
+ int maxProd = nums[0];
+ int maxUntilIndex = nums[0];
+ int minUntilIndex = nums[0];
+
+ for (int i = 1; i < nums.length; i++) {
+ if (nums[i] >= 0) {
+ maxUntilIndex = Math.max(nums[i], maxUntilIndex * nums[i]);
+ minUntilIndex = Math.min(nums[i], minUntilIndex * nums[i]);
+ } else {
+ int prevMaxUntilIndex = maxUntilIndex;
+ maxUntilIndex = Math.max(nums[i], minUntilIndex * nums[i]); // when current number is -ve then multiply with minUntilIndex to get the max as product of two negatives is a positive
+ minUntilIndex = Math.min(nums[i], prevMaxUntilIndex * nums[i]);
+ }
+
+ maxProd = Math.max(maxProd, maxUntilIndex);
+ }
+
+ return maxProd;
+ }
+
+ public static void main(String[] args) {
+ assertEquals(24, maxProduct(new int[]{-2, 3, -4}));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/leetcode/arrays/MaximumSubArray.java b/src/main/java/com/leetcode/dynamicprogramming/MaximumSubArray.java
similarity index 98%
rename from src/main/java/com/leetcode/arrays/MaximumSubArray.java
rename to src/main/java/com/leetcode/dynamicprogramming/MaximumSubArray.java
index f9a64a3f..90a28c93 100644
--- a/src/main/java/com/leetcode/arrays/MaximumSubArray.java
+++ b/src/main/java/com/leetcode/dynamicprogramming/MaximumSubArray.java
@@ -1,4 +1,4 @@
-package com.leetcode.arrays;
+package com.leetcode.dynamicprogramming;
/**
* Level: Easy
diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java
index ae5db698..5692b0d8 100644
--- a/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java
+++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java
@@ -2,7 +2,7 @@
/**
* Level: Easy
- * Problem Link: https://leetcode.com/problems/paint-house/ (premium)
+ * Problem Link: https://leetcode.com/problems/paint-house/
* Problem Description:
* There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. The cost
* of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent
@@ -20,6 +20,8 @@
public class PaintHouse {
/**
+ * Runtime: 1 ms.
+ *
* @param costs of coloring the houses with red, blue, and green respectively. 1st row represents house 1, 2nd row
* house 2 and so on
* @return the minimum cost to paint all houses such that no two adjacent houses are of same color
diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java
index 4c44e28d..431ce612 100644
--- a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java
+++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java
@@ -1,10 +1,10 @@
package com.leetcode.dynamicprogramming;
-import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* Level: Hard
- * Problem Link: https://leetcode.com/problems/paint-house-ii/ (premium)
+ * Problem Link: https://leetcode.com/problems/paint-house-ii/
* Problem Description:
* There are a row of n houses, each house can be painted with one of the m colors.
* The cost of painting each house with a certain color is different.
diff --git a/src/main/java/com/leetcode/graphs/GraphValidTree.java b/src/main/java/com/leetcode/graphs/GraphValidTree.java
new file mode 100644
index 00000000..15950143
--- /dev/null
+++ b/src/main/java/com/leetcode/graphs/GraphValidTree.java
@@ -0,0 +1,131 @@
+package com.leetcode.graphs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Level: Medium
+ * Problem Link: https://leetcode.com/problems/graph-valid-tree/
+ * Problem Description:
+ * Given n nodes labeled from 0 to n-1 and a list of undirected edges (each edge is a pair of nodes), write a function
+ * to check whether these edges make up a valid tree.
+ *
+ * Example 1:
+ * Input: n = 5, and edges = [[0,1], [0,2], [0,3], [1,4]]
+ * Output: true
+ *
+ * Example 2:
+ * Input: n = 5, and edges = [[0,1], [1,2], [2,3], [1,3], [1,4]]
+ * Output: false
+ *
+ * Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0,1] is the
+ * same as [1,0] and thus will not appear together in edges.
+ *
+ * @author rampatra
+ * @since 2019-08-05
+ */
+public class GraphValidTree {
+
+ /**
+ *
+ * @param n
+ * @param edges
+ * @return
+ */
+ public static boolean isValidTree(int n, int[][] edges) {
+ List
+ * Only one letter can be changed at a time. Each transformed word must exist in the word list. Note that beginWord
+ * is not a transformed word.
+ *
+ * Note:
+ * - Return 0 if there is no such transformation sequence.
+ * - All words have the same length.
+ * - All words contain only lowercase alphabetic characters.
+ * - You may assume no duplicates in the word list.
+ * - You may assume beginWord and endWord are non-empty and are not the same.
+ *
+ * Example 1:
+ * Input:
+ * beginWord = "hit",
+ * endWord = "cog",
+ * wordList = ["hot","dot","dog","lot","log","cog"]
+ *
+ * Output: 5
+ *
+ * Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
+ * return its length 5.
+ *
+ * Example 2:
+ * Input:
+ * beginWord = "hit"
+ * endWord = "cog"
+ * wordList = ["hot","dot","dog","lot","log"]
+ *
+ * Output: 0
+ *
+ * Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
+ *
+ * @author rampatra
+ * @since 2019-08-15
+ */
+public class WordLadder {
+
+ /**
+ * Runtime: 79 ms.
+ *
+ * @param beginWord
+ * @param endWord
+ * @param wordList
+ * @return
+ */
+ public static int ladderLength(String beginWord, String endWord, List
+ * Only one letter can be changed at a time
+ * Each transformed word must exist in the word list. Note that beginWord is not a transformed word.
+ *
+ * Note:
+ * - Return an empty list if there is no such transformation sequence.
+ * - All words have the same length.
+ * - All words contain only lowercase alphabetic characters.
+ * - You may assume no duplicates in the word list.
+ * - You may assume beginWord and endWord are non-empty and are not the same.
+ *
+ * Example 1:
+ * Input:
+ * beginWord = "hit",
+ * endWord = "cog",
+ * wordList = ["hot","dot","dog","lot","log","cog"]
+ *
+ * Output:
+ * [
+ * ["hit","hot","dot","dog","cog"],
+ * ["hit","hot","lot","log","cog"]
+ * ]
+ *
+ *
+ * Example 2:
+ * Input:
+ * beginWord = "hit"
+ * endWord = "cog"
+ * wordList = ["hot","dot","dog","lot","log"]
+ *
+ * Output: []
+ * Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.
+ *
+ * @author rampatra
+ * @since 2019-08-15
+ */
+public class WordLadderII {
+
+ /**
+ * The approach is same as {@link WordLadder}. We calculate the {@code minDistance} from start to end word and also
+ * keep a map of words and its adjacent words (i.e, with only character difference). After we are done calculating
+ * the {@code mindistance}, we perform a dfs on the map upto depth {@code minDistance} and if the last word at this
+ * depth is equal to the end word then we add all words to the result.
+ *
+ * @param beginWord
+ * @param endWord
+ * @param wordList
+ * @return
+ */
+ public static List
+ * Time Complexity:
+ * Space Complexity:
+ * Runtime: 38 ms.
+ *
+ * @param s
+ * @return
+ */
+ public static List
+ * Examples:
+ * Assume that words = ["practice", "makes", "perfect", "coding", "makes"].
+ *
+ * Input1: word1 = “coding”, word2 = “practice”
+ * Output1: 3
+ *
+ * Input2: word1 = "makes", word2 = "coding"
+ * Output2: 1
+ *
+ * Note: You may assume that word1 does not equal to word2, and word1 and word2 are both in the list.
+ *
+ * @author rampatra
+ * @since 2019-07-31
+ */
+public class ShortestWordDistanceII {
+
+ private String[] words;
+ private Map
+ * add - Add the number to an internal data structure.
+ * find - Find if there exists any pair of numbers which sum is equal to the value.
+ *
+ * Example 1:
+ * add(1); add(3); add(5);
+ * find(4) -> true
+ * find(7) -> false
+ *
+ * Example 2:
+ * add(3); add(1); add(2);
+ * find(3) -> true
+ * find(6) -> false
+ *
+ * @author rampatra
+ * @since 2019-08-03
+ */
+public class TwoSumIII {
+
+ Map
+ * Example 1:
+ * Input: s = "eceba", k = 2
+ * Output: 3
+ * Explanation: T is "ece" which its length is 3.
+ *
+ * Example 2:
+ * Input: s = "aa", k = 1
+ * Output: 2
+ * Explanation: T is "aa" which its length is 2.
+ *
+ * @author rampatra
+ * @since 2019-08-09
+ */
+public class LongestSubstringWithKDistinctCharacters {
+
+ /**
+ * Time Complexity: O(n)
+ * Space Complexity: O(k), as we keep at most k characters in the hash table
+ *
+ * @param str
+ * @param k
+ * @return
+ */
+ public static int lengthOfLongestSubstringKDistinct(String str, int k) {
+ int length = 0;
+ Map
+ * Example 1:
+ * Input: "abcabcbb"
+ * Output: 3
+ * Explanation: The answer is "abc", with the length of 3.
+ *
+ * Example 2:
+ * Input: "bbbbb"
+ * Output: 1
+ * Explanation: The answer is "b", with the length of 1.
+ *
+ * Example 3:
+ * Input: "pwwkew"
+ * Output: 3
+ * Explanation: The answer is "wke", with the length of 3.
+ * Note that the answer must be a substring, "pwke" is a subsequence and not a substring.
+ *
+ * @author rampatra
+ * @since 2019-08-15
+ */
+public class LongestSubstringWithoutRepeatingCharacters {
+
+ /**
+ * Sliding Window Approach (using map).
+ *
+ * Note:
+ * If we know that the charset is rather small, we can replace the Map with an integer array as direct access table.
+ *
+ * Commonly used tables are:
+ *
+ * int[26] for Letters 'a' - 'z' or 'A' - 'Z'
+ * int[128] for ASCII
+ * int[256] for Extended ASCII
+ *
+ * Runtime: 8 ms.
+ *
+ * @param s
+ * @return
+ */
+ public static int lengthOfLongestSubstring(String s) {
+ int left = 0;
+ int right = 0;
+ int longestSubstringLen = 0;
+ Set
+ * Example:
+ *
+ * Input: S = "ADOBECODEBANC", T = "ABC"
+ * Output: "BANC"
+ *
+ * Note:
+ * - If there is no such window in S that covers all characters in T, return the empty string "".
+ * - If there is such window, you are guaranteed that there will always be only one unique minimum window in S.
+ *
+ * @author rampatra
+ * @since 2019-08-13
+ */
+public class MinimumWindowSubstring {
+
+ /**
+ * Sliding Window Approach (using map).
+ *
+ * Note:
+ * If we know that the charset is rather small, we can replace the Map with an integer array as direct access table.
+ *
+ * Commonly used tables are:
+ *
+ * int[26] for Letters 'a' - 'z' or 'A' - 'Z'
+ * int[128] for ASCII
+ * int[256] for Extended ASCII
+ *
+ * Runtime: 22 ms.
+ *
+ * @param s
+ * @param t
+ * @return
+ */
+ public static String minWindow(String s, String t) {
+
+ int left = 0; // start of window
+ int right = 0; // end of window
+ int begin = 0;
+ int windowSize = Integer.MAX_VALUE;
+ int charsInWindow = 0; // to check whether the window has all the characters in t with the required frequency
+
+ // characters and their counts in t
+ Map
+ * Example 1:
+ * Input: [3,2,1,5,6,4] and k = 2
+ * Output: 5
+ *
+ * Example 2:
+ * Input: [3,2,3,1,2,4,5,5,6] and k = 4
+ * Output: 4
+ *
+ * Note:
+ * You may assume k is always valid, 1 ≤ k ≤ array's length.
+ *
+ * @author rampatra
+ * @since 2019-08-19
+ */
+public class KthLargestElementInArray {
+
+ /**
+ * Runtime: 1 ms.
+ *
+ * @param nums
+ * @param k
+ * @return
+ */
+ public static int findKthLargest(int[] nums, int k) {
+ return heapSortUntilK(nums, k);
+ }
+
+ /**
+ * In heapsort, after each iteration we have the max element at the end of the array. Ergo, if we run the algorithm
+ * k times then we would have our kth largest element.
+ *
+ * @param a
+ * @param k
+ * @return
+ */
+ public static int heapSortUntilK(int[] a, int k) {
+ buildMaxHeap(a);
+ int count = 0;
+
+ for (int i = a.length - 1; i > 0; i--) {
+ if (count++ == k) {
+ break;
+ }
+ swap(a, 0, i);
+ maxHeapify(a, 0, i);
+ }
+
+ return a[a.length - k];
+ }
+
+ /**
+ * Makes the array {@param a} satisfy the max heap property starting from
+ * {@param index} till {@param end} position in array.
+ *
+ * Example 1:
+ * Input: nums = [1,1,1,2,2,3], k = 2
+ * Output: [1,2]
+ *
+ * Example 2:
+ * Input: nums = [1], k = 1
+ * Output: [1]
+ *
+ * Note:
+ * - You may assume k is always valid, 1 ≤ k ≤ number of unique elements.
+ * - Your algorithm's time complexity must be better than O(n log n), where n is the array's size.
+ *
+ * @author rampatra
+ * @since 2019-08-19
+ */
+public class TopKFrequentElements {
+
+ /**
+ * TODO: A faster approach without using Pair.
+ *
+ * Runtime: 51 ms.
+ *
+ * @param nums
+ * @param k
+ * @return
+ */
+ public static List
+ * Example 1:
+ * Given the list [[1,1],2,[1,1]], return 10. (four 1’s at depth 2, one 2 at depth 1)
+ *
+ * Example 2:
+ * Given the list [1,[4,[6]]], return 27. (one 1 at depth 1, one 4 at depth 2, and one 6 at depth 3; 1 + 42 + 63 = 27)
+ *
+ * Note: For a more complex variant, see {@link NestedListWeightSumII}.
+ *
+ * @author rampatra
+ * @since 2019-07-27
+ */
+public class NestedListWeightSum {
+
+ /**
+ * Time Complexity: The algorithm takes O(N) time, where N is the total number of nested elements in the input
+ * list. For example, the list [ [[[[1]]]], 2 ] contains 4 nested lists and 2 nested integers (11 and 22), so N=6.
+ * Space Complexity: In terms of space, at most O(D) recursive calls are placed on the stack, where D is the
+ * maximum level of nesting in the input. For example, D=2 for the input [[1,1],2,[1,1]], and D=3 for the
+ * input [1,[4,[6]]].
+ *
+ * @param nestedList
+ * @return
+ */
+ public static long nestedSum(Object[] nestedList) {
+ return nestedSum(nestedList, 1);
+ }
+
+ private static long nestedSum(Object[] nestedList, int depth) {
+ long sum = 0;
+ for (int i = 0; i < nestedList.length; i++) {
+ if (nestedList[i] instanceof Integer) {
+ sum += ((int) nestedList[i] * depth);
+ } else {
+ sum += nestedSum((Object[]) nestedList[i], depth + 1);
+ }
+ }
+ return sum;
+ }
+
+ public static void main(String[] args) {
+ assertEquals(0, nestedSum(new Object[]{}));
+ assertEquals(0, nestedSum(new Object[]{new Object[]{}}));
+ assertEquals(10, nestedSum(new Object[]{new Object[]{1, 1}, 2, new Object[]{1, 1}}));
+ assertEquals(27, nestedSum(new Object[]{1, new Object[]{4, new Object[]{6}}}));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/leetcode/recursion/NestedListWeightSumII.java b/src/main/java/com/leetcode/recursion/NestedListWeightSumII.java
new file mode 100644
index 00000000..eadd121b
--- /dev/null
+++ b/src/main/java/com/leetcode/recursion/NestedListWeightSumII.java
@@ -0,0 +1,80 @@
+package com.leetcode.recursion;
+
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Level: Medium
+ * Problem Link: https://leetcode.com/problems/nested-list-weight-sum-ii/
+ * Problem Description:
+ * Given a nested list of integers, return the sum of all integers in the list weighted by their depth. Each element
+ * is either an integer, or a list – whose elements may also be integers or other lists.
+ *
+ * Different from {@link NestedListWeightSum} where weight is increasing from root to leaf, now the weight is defined
+ * from bottom up, i.e., the leaf level integers have weight 1, and the root level integers have the largest weight.
+ *
+ * Example 1:
+ * Given the list [[1,1],2,[1,1]], return 8. (four 1’s at depth 1, one 2 at depth 2)
+ *
+ * Example 2:
+ * Given the list [1,[4,[6]]], return 17. (one 1 at depth 3, one 4 at depth 2, and one 6 at depth 1; 13 + 42 + 6*1 = 17)
+ *
+ * Note: For a simpler variant, see {@link NestedListWeightSum}.
+ *
+ * @author rampatra
+ * @since 2019-07-27
+ */
+public class NestedListWeightSumII {
+
+ /**
+ * Time Complexity:
+ * Space Complexity:
+ * Runtime: 1 ms.
+ *
+ * @param nestedList
+ * @return
+ */
+ public static int nestedSum(List
+ * Valid operators are +, -, *, /. Each operand may be an integer or another expression.
+ *
+ * Note:
+ * Division between two integers should truncate toward zero.
+ * The given RPN expression is always valid. That means the expression would always evaluate to a result and there
+ * won't be any divide by zero operation.
+ *
+ * Example 1:
+ * Input: ["2", "1", "+", "3", "*"]
+ * Output: 9
+ * Explanation: ((2 + 1) * 3) = 9
+ *
+ * Example 2:
+ * Input: ["4", "13", "5", "/", "+"]
+ * Output: 6
+ * Explanation: (4 + (13 / 5)) = 6
+ *
+ * Example 3:
+ * Input: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
+ * Output: 22
+ * Explanation:
+ * ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
+ * = ((10 * (6 / (12 * -11))) + 17) + 5
+ * = ((10 * (6 / -132)) + 17) + 5
+ * = ((10 * 0) + 17) + 5
+ * = (0 + 17) + 5
+ * = 17 + 5
+ * = 22
+ *
+ * @author rampatra
+ * @since 2019-07-27
+ */
+public class ReversePolishNotation {
+
+ /**
+ * Time Complexity:
+ * Space Complexity:
+ * Runtime: 5 ms.
+ *
+ * @param tokens
+ * @return
+ */
+ public static int evalRPN(String[] tokens) {
+ int operand1;
+ int operand2;
+
+ Stack
- * Runtime: 7 ms on leetcode.
+ * Runtime: 6 ms.
*
* @param text
* @param pattern
diff --git a/src/main/java/com/leetcode/trees/BinaryTreeUpsideDown.java b/src/main/java/com/leetcode/trees/BinaryTreeUpsideDown.java
new file mode 100644
index 00000000..aa43bf50
--- /dev/null
+++ b/src/main/java/com/leetcode/trees/BinaryTreeUpsideDown.java
@@ -0,0 +1,207 @@
+package com.leetcode.trees;
+
+import java.util.Stack;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+/**
+ * Level: Medium
+ * Problem Link: https://leetcode.com/problems/binary-tree-upside-down/
+ * Problem Description:
+ * Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that shares the
+ * same parent node) or empty, flip it upside down and turn it into a tree where the original right nodes turned into
+ * left leaf nodes. Return the new root.
+ *
+ * Example:
+ * Input: [1,2,3,4,5]
+ *
+ * 1
+ * / \
+ * 2 3
+ * / \
+ * 4 5
+ *
+ * Output: return the root of the binary tree [4,5,2,#,#,3,1]
+ *
+ * 4
+ * / \
+ * 5 2
+ * / \
+ * 3 1
+ *
+ * Clarification:
+ * Confused what [4,5,2,#,#,3,1] means? Read more below on how binary tree is serialized on OJ. The serialization of
+ * a binary tree follows a level order traversal, where '#' signifies a path terminator where no node exists below.
+ *
+ * Here's an example:
+ *
+ * 1
+ * / \
+ * 2 3
+ * /
+ * 4
+ * \
+ * 5
+ *
+ * The above binary tree is serialized as [1,2,3,#,#,4,#,#,5].
+ *
+ * @author rampatra
+ * @since 2019-08-04
+ */
+public class BinaryTreeUpsideDown {
+
+ /**
+ * The solution is simple, every node (except the root) on the left of the tree would have its parent's right child
+ * as it's left child and parent as its right child. That's all you have to do to flip the tree upside down.
+ *
+ * Time Complexity: O(h)
+ * Space Complexity: O(h)
+ * where,
+ * h = height of the tree
+ *
+ * Runtime: 1 ms.
+ *
+ * @param root
+ * @return
+ */
+ public static TreeNode upsideDownBinaryTreeUsingStack(TreeNode root) {
+ if (root == null) return null;
+
+ TreeNode curr = root;
+ TreeNode currParent;
+ TreeNode newRoot = null;
+
+ // using stack to keep track of the parent node
+ Stack
+ * Note:
+ * - Given target value is a floating point.
+ * - You are guaranteed to have only one unique value in the BST that is closest to the target.
+ *
+ * @author rampatra
+ * @since 2019-07-31
+ */
+public class ClosestBinarySearchTreeValue {
+
+ /**
+ * Runtime: 0 ms.
+ *
+ * @param root
+ * @param target
+ * @return
+ */
+ public static int closestValue(TreeNode root, double target) {
+ if (root == null) return -1;
+
+ return closestValue(root, root, target);
+ }
+
+ private static int closestValue(TreeNode node, TreeNode closestNode, double val) {
+ if (node == null) return closestNode.val;
+
+ if (Math.abs(node.val - val) < Math.abs(closestNode.val - val)) {
+ closestNode = node;
+ }
+
+ if (node.val > val) {
+ return closestValue(node.left, closestNode, val);
+ } else {
+ return closestValue(node.right, closestNode, val);
+ }
+ }
+
+ public static void main(String[] args) {
+
+ /*
+ BST looks like:
+
+ 9
+ / \
+ 7 13
+ / \ \
+ 5 8 20
+ / \
+ 2 6
+ */
+ TreeNode root = new TreeNode(9);
+ root.left = new TreeNode(7);
+ root.right = new TreeNode(13);
+ root.left.left = new TreeNode(5);
+ root.left.right = new TreeNode(8);
+ root.left.left.right = new TreeNode(6);
+ root.left.left.left = new TreeNode(2);
+ root.right.right = new TreeNode(20);
+
+ assertEquals(13, closestValue(root, 15));
+ assertEquals(13, closestValue(root, 13));
+ assertEquals(9, closestValue(root, 9));
+ assertEquals(2, closestValue(root, 2));
+ assertEquals(2, closestValue(root, 1));
+ assertEquals(6, closestValue(root, 6));
+ assertEquals(13, closestValue(root, 11)); // tie b/w 9 and 13
+
+ /*
+ BST looks like:
+
+ 9
+ / \
+ 7 13
+ / \ / \
+ 5 8 13 20
+ */
+ root = new TreeNode(9);
+ root.left = new TreeNode(7);
+ root.right = new TreeNode(13);
+ root.left.left = new TreeNode(5);
+ root.left.right = new TreeNode(8);
+ root.right.left = new TreeNode(13);
+ root.right.right = new TreeNode(20);
+
+ assertEquals(13, closestValue(root, 15));
+
+ /*
+ BST looks like:
+
+ 1500000000
+ /
+ /
+ /
+ 1400000000
+ */
+ root = new TreeNode(1500000000);
+ root.left = new TreeNode(1400000000);
+
+ assertEquals(1400000000, closestValue(root, -1500000000.0));
+ }
+}
diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java
new file mode 100644
index 00000000..e583723a
--- /dev/null
+++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java
@@ -0,0 +1,166 @@
+package com.leetcode.trees;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.Stack;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Level: Hard
+ * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value-ii/
+ * Problem Description:
+ * Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target.
+ *
+ * Note:
+ * - Given target value is a floating point.
+ * - You may assume k is always valid, that is: k ≤ total nodes.
+ * - You are guaranteed to have only one unique set of k values in the BST that are closest to the target.
+ *
+ * Example:
+ * Input: root = [4,2,5,1,3], target = 3.714286, and k = 2
+ *
+ * 4
+ * / \
+ * 2 5
+ * / \
+ * 1 3
+ *
+ * Output: [4,3]
+ *
+ * Follow up:
+ * Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)?
+ *
+ * @author rampatra
+ * @since 2019-07-31
+ */
+public class ClosestBinarySearchTreeValueII {
+
+
+ /**
+ * The idea is simple. We do the inorder traversal and keep the values less than or equal to target in a stack and
+ * the values greater than target in a queue. And finally, we compare values from both stack and queue and take
+ * whichever is the closest to target value each time.
+ *
+ * Note: We can optimize it even further in terms of space. We can get rid of the stack and queue and just fill up
+ * the result list in the recursive inOrder call. Once the result list is of size k, we can compare and remove the
+ * farthest value and insert the closer value. See {@link ClosestBinarySearchTreeValueII#closestKValuesOptimized(TreeNode, double, int)}.
+ *
+ * @param root
+ * @param target
+ * @param k
+ * @return
+ */
+ public static List> adjacencyList = new ArrayList<>(n);
+
+ for (int i = 0; i < n; i++) {
+ adjacencyList.add(new ArrayList<>());
+ }
+
+ for (int i = 0; i < edges.length; i++) {
+ adjacencyList.get(edges[i][0]).add(edges[i][1]);
+ }
+
+ boolean[] visited = new boolean[n];
+
+ if (hasCycle(adjacencyList, 0, -1, visited)) {
+ return false;
+ }
+
+ for (int i = 0; i < n; i++) {
+ if (!visited[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static boolean hasCycle(List
> adjacencyList, int node1, int exclude, boolean[] visited) {
+ visited[node1] = true;
+
+ for (int i = 0; i < adjacencyList.get(node1).size(); i++) {
+ int node2 = adjacencyList.get(node1).get(i);
+
+ if ((visited[node2] && exclude != node2) || (!visited[node2] && hasCycle(adjacencyList, node2, node1, visited))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * Union-find algorithm: We keep all connected nodes in one set in the union operation and in find operation we
+ * check whether two nodes belong to the same set. If yes then there's a cycle and if not then no cycle.
+ *
+ * Good articles on union-find:
+ * - https://www.hackerearth.com/practice/notes/disjoint-set-union-union-find/
+ * - https://www.youtube.com/watch?v=wU6udHRIkcc
+ *
+ * @param n
+ * @param edges
+ * @return
+ */
+ public static boolean isValidTreeUsingUnionFind(int n, int[][] edges) {
+ int[] roots = new int[n];
+
+ for (int i = 0; i < n; i++) {
+ roots[i] = i;
+ }
+
+ for (int i = 0; i < edges.length; i++) {
+ // find operation
+ if (roots[edges[i][0]] == roots[edges[i][1]]) {
+ return false;
+ }
+ // union operation
+ roots[edges[i][1]] = findRoot(roots, roots[edges[i][0]]); // note: we can optimize this even further by
+ // considering size of each side and then join the side with smaller size to the one with a larger size (weighted union).
+ // We can use another array called size to keep count of the size or we can use the same root array with
+ // negative values, i.e, negative resembles that the node is pointing to itself and the number will represent
+ // the size. For example, roots = [-2, -1, -1, 0] means that node 3 is pointing to node 0 and node 0 is pointing
+ // to itself and is has 2 nodes under it including itself.
+ }
+
+ return edges.length == n - 1;
+ }
+
+ private static int findRoot(int[] roots, int node) {
+ while (roots[node] != node) {
+ node = roots[node];
+ }
+ return node;
+ }
+
+ public static void main(String[] args) {
+ assertTrue(isValidTree(5, new int[][]{{0, 1}, {0, 2}, {0, 3}, {1, 4}}));
+ assertFalse(isValidTree(5, new int[][]{{0, 1}, {1, 2}, {2, 3}, {1, 3}, {1, 4}}));
+ assertFalse(isValidTree(3, new int[][]{{0, 1}, {1, 2}, {2, 0}}));
+
+ assertTrue(isValidTreeUsingUnionFind(5, new int[][]{{0, 1}, {0, 2}, {0, 3}, {1, 4}}));
+ assertFalse(isValidTreeUsingUnionFind(5, new int[][]{{0, 1}, {1, 2}, {2, 3}, {1, 3}, {1, 4}}));
+ assertFalse(isValidTreeUsingUnionFind(3, new int[][]{{0, 1}, {1, 2}, {2, 0}}));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/leetcode/graphs/WordLadder.java b/src/main/java/com/leetcode/graphs/WordLadder.java
new file mode 100644
index 00000000..61e706ce
--- /dev/null
+++ b/src/main/java/com/leetcode/graphs/WordLadder.java
@@ -0,0 +1,121 @@
+package com.leetcode.graphs;
+
+
+import javafx.util.Pair;
+
+import java.util.*;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Level: Medium
+ * Link: https://leetcode.com/problems/word-ladder/
+ * Description:
+ * Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation
+ * sequence from beginWord to endWord, such that:
+ *
> findLadders(String beginWord, String endWord, List
> ladders = new LinkedList<>();
+ Map
> ladders, Set
> homeCoordinates = new ArrayList<>();
+
+ for (int i = 0; i < grid.length; i++) {
+ for (int j = 0; j < grid[0].length; j++) {
+ if (grid[i][j] == 1) {
+ homeCoordinates.add(Arrays.asList(i, j));
+ }
+ }
+ }
+
+ for (int i = 0; i < grid.length; i++) {
+ for (int j = 0; j < grid[0].length; j++) {
+ int distance = 0;
+ for (int k = 0; k < homeCoordinates.size(); k++) {
+ distance += Math.abs(homeCoordinates.get(k).get(0) - i) + Math.abs(homeCoordinates.get(k).get(1) - j);
+ }
+ minDistance = Math.min(minDistance, distance);
+ }
+ }
+
+ return minDistance;
+ }
+
+ public static int minTotalDistance(int[][] grid) {
+ return -1; // todo
+ }
+
+ public static void main(String[] args) {
+ assertEquals(6, minTotalDistanceBrutForce(new int[][]{
+ {1,0,0,0,1},
+ {0,0,0,0,0},
+ {0,0,1,0,0}
+ }));
+
+ assertEquals(4, minTotalDistanceBrutForce(new int[][]{
+ {1,0,0,0,1},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+
+ assertEquals(1, minTotalDistanceBrutForce(new int[][]{
+ {1,1,0,0,0},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+
+ assertEquals(0, minTotalDistanceBrutForce(new int[][]{
+ {1,0,0,0,0},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+
+ assertEquals(0, minTotalDistanceBrutForce(new int[][]{
+ {0,0,0,0,0},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+
+ assertEquals(6, minTotalDistance(new int[][]{
+ {1,0,0,0,1},
+ {0,0,0,0,0},
+ {0,0,1,0,0}
+ }));
+
+ assertEquals(4, minTotalDistance(new int[][]{
+ {1,0,0,0,1},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+
+ assertEquals(1, minTotalDistance(new int[][]{
+ {1,1,0,0,0},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+
+ assertEquals(0, minTotalDistance(new int[][]{
+ {1,0,0,0,0},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+
+ assertEquals(0, minTotalDistance(new int[][]{
+ {0,0,0,0,0},
+ {0,0,0,0,0},
+ {0,0,0,0,0}
+ }));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/leetcode/recursion/FlattenNestListIterator.java b/src/main/java/com/leetcode/recursion/FlattenNestListIterator.java
new file mode 100644
index 00000000..b443e954
--- /dev/null
+++ b/src/main/java/com/leetcode/recursion/FlattenNestListIterator.java
@@ -0,0 +1,69 @@
+package com.leetcode.recursion;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Level: Medium
+ * Link: https://leetcode.com/problems/flatten-nested-list-iterator/
+ * Description:
+ * Given a nested list of integers, implement an iterator to flatten it.
+ *
+ * Each element is either an integer, or a list -- whose elements may also be integers or other lists.
+ *
+ * Example 1:
+ * Input: [[1,1],2,[1,1]]
+ * Output: [1,1,2,1,1]
+ * Explanation: By calling next repeatedly until hasNext returns false,
+ * the order of elements returned by next should be: [1,1,2,1,1].
+ *
+ * Example 2:
+ * Input: [1,[4,[6]]]
+ * Output: [1,4,6]
+ * Explanation: By calling next repeatedly until hasNext returns false,
+ * the order of elements returned by next should be: [1,4,6].
+ *
+ * Runtime: 2 ms.
+ *
+ * @author rampatra
+ * @since 2019-08-12
+ */
+public class FlattenNestListIterator implements Iterator
> zigzagLevelOrder(TreeNode root) {
+
+ int levelNo = 0;
+ LinkedList
> levelOrderTraversal = new LinkedList<>();
+
+ if (root == null) {
+ return levelOrderTraversal;
+ }
+
+ Queue
> findLeavesOfBinaryTree(TreeNode root) {
+ List
> levels = new ArrayList<>();
+ findLeavesOfBinaryTree(root, levels);
+ return levels;
+ }
+
+ private static int findLeavesOfBinaryTree(TreeNode root, List
> levels) {
+ if (root == null) return -1;
+
+ int leftHeight = findLeavesOfBinaryTree(root.left, levels);
+ int rightHeight = findLeavesOfBinaryTree(root.right, levels);
+ int height = Math.max(leftHeight, rightHeight) + 1;
+
+ if (height >= levels.size()) {
+ levels.add(height, new ArrayList<>());
+ }
+ levels.get(height).add(root.val);
+
+ return height;
+ }
+
+ public static void main(String[] args) {
+ /*
+ BST looks like:
+
+ 4
+ / \
+ 1 7
+ / \ \
+ 3 8 20
+ / \
+ 2 6
+ */
+ TreeNode root = new TreeNode(4);
+ root.left = new TreeNode(1);
+ root.right = new TreeNode(7);
+ root.left.left = new TreeNode(3);
+ root.left.right = new TreeNode(8);
+ root.left.left.left = new TreeNode(2);
+ root.left.left.right = new TreeNode(6);
+ root.right.right = new TreeNode(20);
+
+ assertEquals("[[2, 6, 8, 20], [3, 7], [1], [4]]", findLeavesOfBinaryTree(root).toString());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/leetcode/trees/SecondMinNodeInBinaryTree.java b/src/main/java/com/leetcode/trees/SecondMinNodeInBinaryTree.java
new file mode 100644
index 00000000..a8cddf74
--- /dev/null
+++ b/src/main/java/com/leetcode/trees/SecondMinNodeInBinaryTree.java
@@ -0,0 +1,108 @@
+package com.leetcode.trees;
+
+import java.util.Stack;
+
+/**
+ * Level: Easy
+ * Problem Link: https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/
+ * Problem Description:
+ * Given a non-empty special binary tree consisting of nodes with the non-negative value, where each node in this
+ * tree has exactly two or zero sub-node. If the node has two sub-nodes, then this node's value is the smaller value
+ * among its two sub-nodes. More formally, the property root.val = min(root.left.val, root.right.val) always holds.
+ *
+ * Given such a binary tree, you need to output the second minimum value in the set made of all the nodes' value in
+ * the whole tree.
+ *
+ * If no such second minimum value exists, output -1 instead.
+ *
+ * Example 1:
+ * Input:
+ * 2
+ * / \
+ * 2 5
+ * / \
+ * 5 7
+ *
+ * Output: 5
+ * Explanation: The smallest value is 2, the second smallest value is 5.
+ *
+ *
+ * Example 2:
+ * Input:
+ * 2
+ * / \
+ * 2 2
+ *
+ * Output: -1
+ * Explanation: The smallest value is 2, but there isn't any second smallest value.
+ *
+ * @author rampatra
+ * @since 2019-08-03
+ */
+public class SecondMinNodeInBinaryTree {
+
+ /**
+ * Time Complexity: O(n)
+ * Space Complexity: O(n)
+ * Runtime: 1 ms.
+ * @param root
+ * @return
+ */
+ public static int findSecondMinimumValueIterative(TreeNode root) {
+ if (root == null || (root.left == null && root.right == null)) return -1;
+
+ int min = root.val;
+ long secondMin = Long.MAX_VALUE;
+
+ Stack