- * 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/hackerrank/java/advanced/JavaVisitorPattern.java b/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java
index a40151be..5f91e9b5 100644
--- a/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java
+++ b/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java
@@ -1,8 +1,226 @@
package com.hackerrank.java.advanced;
+import java.util.*;
+
/**
+ * Level: Medium
+ * Problem Link: https://www.hackerrank.com/challenges/java-vistor-pattern/
+ *
* @author rampatra
* @since 2019-06-22
*/
-public class JavaVisitorPattern {
+enum Color {
+ RED, GREEN
+}
+
+abstract class Tree {
+
+ private int value;
+ private Color color;
+ private int depth;
+
+ public Tree(int value, Color color, int depth) {
+ this.value = value;
+ this.color = color;
+ this.depth = depth;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public Color getColor() {
+ return color;
+ }
+
+ public int getDepth() {
+ return depth;
+ }
+
+ public abstract void accept(TreeVis visitor);
+
+
+}
+
+class TreeNode extends Tree {
+
+ private ArrayList
* 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
new file mode 100644
index 00000000..916499ac
--- /dev/null
+++ b/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java
@@ -0,0 +1,68 @@
+package com.leetcode.arrays;
+
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Level: Easy
+ * Problem Link: https://leetcode.com/problems/can-place-flowers/
+ * Problem Description:
+ * Suppose you have a long flowerBed in which some of the plots are planted and some are not. However, flowers cannot
+ * be planted in adjacent plots - they would compete for water and both would die.
+ *
+ * Given a flowerBed (represented as an array containing 0 and 1, where 0 means empty and 1 means not empty), and a
+ * number n, return if n new flowers can be planted in it without violating the no-adjacent-flowers rule.
+ *
+ * Example 1:
+ * Input: flowerBed = [1,0,0,0,1], n = 1
+ * Output: True
+ *
+ * Example 2:
+ * Input: flowerBed = [1,0,0,0,1], n = 2
+ * Output: False
+ *
+ * Note:
+ * The input array won't violate no-adjacent-flowers rule.
+ * The input array size is in the range of [1, 20000].
+ * n is a non-negative integer which won't exceed the input array size.
+ *
+ * @author rampatra
+ * @since 2019-07-24
+ */
+public class CanPlaceFlowers {
+
+ /**
+ * Time Complexity: O(n)
+ * Space Complexity: O(1)
+ * Runtime: 1 ms.
+ *
+ * @param flowerBed
+ * @param n
+ * @return
+ */
+ public static boolean canPlaceFlowers(int[] flowerBed, int n) {
+ int i = 0, count = 0;
+ while (i < flowerBed.length) {
+ if (flowerBed[i] == 0 && (i == 0 || flowerBed[i - 1] == 0) && (i == flowerBed.length - 1 || flowerBed[i + 1] == 0)) {
+ flowerBed[i++] = 1;
+ count++;
+ }
+ if (count >= n)
+ return true;
+ i++;
+ }
+ return false;
+ }
+
+ public static void main(String[] args) {
+ assertTrue(canPlaceFlowers(new int[]{0}, 0));
+ assertTrue(canPlaceFlowers(new int[]{0}, 1));
+ assertTrue(canPlaceFlowers(new int[]{1}, 0));
+ assertFalse(canPlaceFlowers(new int[]{1}, 1));
+ assertTrue(canPlaceFlowers(new int[]{1, 0, 0, 0, 1}, 1));
+ assertFalse(canPlaceFlowers(new int[]{1, 0, 0, 0, 1}, 2));
+ assertFalse(canPlaceFlowers(new int[]{1, 0, 0, 0, 0, 1}, 2));
+ assertTrue(canPlaceFlowers(new int[]{1, 0, 0, 0, 1, 0, 0}, 2));
+ }
+}
\ No newline at end of file
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/InsertInterval.java b/src/main/java/com/leetcode/arrays/InsertInterval.java
new file mode 100644
index 00000000..52155f19
--- /dev/null
+++ b/src/main/java/com/leetcode/arrays/InsertInterval.java
@@ -0,0 +1,78 @@
+package com.leetcode.arrays;
+
+import java.util.Arrays;
+
+/**
+ * Level: Hard
+ * Problem Link: https://leetcode.com/problems/insert-interval/
+ * Problem Description:
+ * Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
+ *
+ * You may assume that the intervals were initially sorted according to their start times.
+ *
+ * Example 1:
+ * Input: intervals = [[1,3],[6,9]], newInterval = [2,5]
+ * Output: [[1,5],[6,9]]
+ *
+ * Example 2:
+ * Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
+ * Output: [[1,2],[3,10],[12,16]]
+ * Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10].
+ *
+ * Companies: LinkedIn.
+ * Related: {@link MergeIntervals}.
+ *
+ * @author rampatra
+ * @since 2019-07-23
+ */
+public class InsertInterval {
+
+ /**
+ * Time Complexity: O(n)
+ * Space Complexity: O(n)
+ * Runtime: 2 ms.
+ *
+ * @param intervals
+ * @param newInterval
+ * @return
+ */
+ public static int[][] insert(int[][] intervals, int[] newInterval) {
+ if (intervals.length == 0 && newInterval.length == 0) {
+ return new int[][]{};
+ } else if (intervals.length == 0) {
+ return new int[][]{newInterval};
+ }
+
+ int[][] mergedIntervals = new int[intervals.length + 1][2];
+ int j = 0;
+
+ for (int i = 0; i < intervals.length; i++) {
+ if (newInterval == null || newInterval[0] > intervals[i][1]) { // newInterval is after the ith interval
+ mergedIntervals[j++] = intervals[i];
+ } else if (newInterval[1] < intervals[i][0]) { // newInterval is before the ith interval
+ mergedIntervals[j++] = newInterval;
+ mergedIntervals[j++] = intervals[i];
+ newInterval = null;
+ } else { // if overlapping
+ newInterval[0] = Math.min(newInterval[0], intervals[i][0]);
+ newInterval[1] = Math.max(newInterval[1], intervals[i][1]);
+ }
+ }
+
+ if (newInterval != null) {
+ mergedIntervals[j++] = newInterval;
+ }
+
+ return Arrays.copyOfRange(mergedIntervals, 0, j);
+ }
+
+ public static void main(String[] args) {
+ System.out.println(Arrays.deepToString(insert(new int[][]{}, new int[]{})));
+ System.out.println(Arrays.deepToString(insert(new int[][]{}, new int[]{5, 7})));
+ System.out.println(Arrays.deepToString(insert(new int[][]{{1, 5}}, new int[]{0, 0})));
+ System.out.println(Arrays.deepToString(insert(new int[][]{{1, 5}}, new int[]{2, 3})));
+ System.out.println(Arrays.deepToString(insert(new int[][]{{2, 5}, {6, 7}, {8, 9}}, new int[]{0, 1})));
+ System.out.println(Arrays.deepToString(insert(new int[][]{{1, 3}, {6, 9}}, new int[]{2, 5})));
+ System.out.println(Arrays.deepToString(insert(new int[][]{{1, 2}, {3, 5}, {6, 7}, {8, 10}, {12, 16}}, new int[]{4, 8})));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/leetcode/arrays/MergeIntervals.java b/src/main/java/com/leetcode/arrays/MergeIntervals.java
new file mode 100644
index 00000000..58f56ebc
--- /dev/null
+++ b/src/main/java/com/leetcode/arrays/MergeIntervals.java
@@ -0,0 +1,78 @@
+package com.leetcode.arrays;
+
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * Level: Medium
+ * Problem Link: https://leetcode.com/problems/merge-intervals/
+ * Problem Description:
+ *
+ * Given a collection of intervals, merge all overlapping intervals.
+ *
+ * Example 1:
+ * Input: [[1,3],[2,6],[8,10],[15,18]]
+ * Output: [[1,6],[8,10],[15,18]]
+ * Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
+ *
+ * Example 2:
+ * Input: [[1,4],[4,5]]
+ * Output: [[1,5]]
+ * Explanation: Intervals [1,4] and [4,5] are considered overlapping.
+ *
+ * Companies: LinkedIn
+ * Related: {@link InsertInterval}.
+ *
+ * @author rampatra
+ * @since 2019-07-22
+ */
+public class MergeIntervals {
+
+ /**
+ * Time complexity: O(n log n)
+ * Space complexity: O(n)
+ * Runtime: 6 ms
+ *
+ * @param intervals a list of intervals, may not be sorted
+ * @return a list of intervals, with overlapping intervals merged
+ */
+ public static int[][] merge(int[][] intervals) {
+ // some validations
+ if (intervals.length == 0) return new int[0][2];
+
+ // we first sort the intervals based on their start times
+ Arrays.sort(intervals, new IntervalComparator());
+
+ int[][] mergedIntervals = new int[intervals.length][2];
+ int lastMergedIndex = 0;
+ mergedIntervals[lastMergedIndex] = intervals[0];
+
+ for (int i = 1; i < intervals.length; i++) {
+ if (isOverlap(mergedIntervals[lastMergedIndex], intervals[i])) {
+ // if two intervals overlap, then merge the two
+ mergedIntervals[lastMergedIndex] = new int[]{Math.min(mergedIntervals[lastMergedIndex][0], intervals[i][0]),
+ Math.max(mergedIntervals[lastMergedIndex][1], intervals[i][1])};
+ } else {
+ mergedIntervals[++lastMergedIndex] = intervals[i];
+ }
+ }
+
+ return Arrays.copyOfRange(mergedIntervals, 0, lastMergedIndex + 1);
+ }
+
+ private static boolean isOverlap(int[] interval1, int[] interval2) {
+ return interval1[0] <= interval2[0] && interval1[1] >= interval2[0];
+ }
+
+ private static class IntervalComparator implements Comparator
+ * 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
new file mode 100644
index 00000000..5692b0d8
--- /dev/null
+++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java
@@ -0,0 +1,52 @@
+package com.leetcode.dynamicprogramming;
+
+/**
+ * Level: Easy
+ * 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
+ * houses have the same color. The cost of painting each house with a certain color is represented by a n x 3 cost matrix.
+ *
+ * For example, costs[0][0] is the cost of painting house 0 with color red; costs[1][2] is the cost of painting
+ * house 1 with color green, and so on... Find the minimum cost to paint all houses.
+ *
+ * Companies: LinkedIn.
+ * Related: {@link PaintHouseII}.
+ *
+ * @author rampatra
+ * @since 2019-07-23
+ */
+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
+ */
+ public static int minCost(int[][] costs) {
+ if (costs == null || costs.length == 0) return 0;
+
+ for (int i = 1; i < costs.length; i++) {
+ costs[i][0] += Math.min(costs[i - 1][1], costs[i - 1][2]);
+ costs[i][1] += Math.min(costs[i - 1][0], costs[i - 1][2]);
+ costs[i][2] += Math.min(costs[i - 1][0], costs[i - 1][1]);
+ }
+
+ int lastRow = costs.length - 1;
+ return Math.min(Math.min(costs[lastRow][0], costs[lastRow][1]), costs[lastRow][2]);
+ }
+
+ public static void main(String[] args) {
+ System.out.println(minCost(new int[][]{
+ }));
+
+ System.out.println(minCost(new int[][]{
+ {2, 3, 4},
+ {5, 7, 6},
+ {8, 7, 2}
+ }));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java
new file mode 100644
index 00000000..431ce612
--- /dev/null
+++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java
@@ -0,0 +1,120 @@
+package com.leetcode.dynamicprogramming;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Level: Hard
+ * 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.
+ * You have to paint all the houses such that no two adjacent houses have the same color.
+ *
+ * The cost of painting each house with a certain color is represented by a n x m cost matrix.
+ *
+ * For example, costs[0][0] is the cost of painting house 0 with color 0;
+ * costs[1][2] is the cost of painting house 1 with color 2, and so on...
+ * Find the minimum cost to paint all houses.
+ *
+ * Note: All costs are positive integers.
+ *
+ * Follow up: Could you solve it in O(n * m) runtime? // TODO
+ *
+ * Companies: LinkedIn.
+ * Related: {@link PaintHouse}.
+ *
+ * @author rampatra
+ * @since 2019-07-24
+ */
+public class PaintHouseII {
+
+ /**
+ * The approach is similar to {@link PaintHouse} but slightly complex as the number of colors are arbitrary
+ * instead of the 3 fixed colors. So, we use two additional for loops to cycle through all the colors.
+ * Time Complexity: O(n * m * m)
+ * Space Complexity: O(1)
+ *
+ * @param costs the costs of coloring the house, each row represents the cost of coloring a particular
+ * house with different colors
+ * @return the minimum cost to paint all houses such that no two adjacent houses are of same color
+ */
+ public static int minCost(int[][] costs) {
+ if (costs == null || costs.length == 0) return 0;
+
+ for (int i = 1; i < costs.length; i++) {
+ for (int j = 0; j < costs[0].length; j++) {
+ int min = Integer.MAX_VALUE;
+ // loop through all colors for the previous house except the color of the current house
+ for (int k = 0; k < costs[0].length; k++) {
+ if (k != j) {
+ min = Math.min(costs[i - 1][k], min);
+ }
+ }
+ costs[i][j] += min;
+ }
+ }
+
+ int minCost = Integer.MAX_VALUE;
+ for (int i = 0; i < costs[0].length; i++) {
+ minCost = Math.min(costs[costs.length - 1][i], minCost);
+ }
+
+ return minCost;
+ }
+
+ public static void main(String[] args) {
+ assertEquals(0, minCost(new int[][]{}));
+
+ assertEquals(10, minCost(new int[][]{
+ {2, 3, 4},
+ {5, 7, 6},
+ {8, 7, 2}
+ }));
+
+ assertEquals(10, minCost(new int[][]{{10, 30, 20}}));
+
+ assertEquals(3, minCost(new int[][]{{1, 1, 1},
+ {1, 1, 1},
+ {1, 1, 1}}));
+
+ assertEquals(5, minCost(new int[][]{{1, 2, 3},
+ {3, 2, 1},
+ {2, 2, 2},
+ {3, 1, 2}}));
+
+ assertEquals(10, minCost(new int[][]{{17, 2, 17},
+ {16, 16, 5},
+ {14, 3, 19}}));
+
+ assertEquals(5, minCost(new int[][]{{1, 5, 3},
+ {2, 9, 4}}));
+
+ assertEquals(8, minCost(new int[][]{{8}}));
+
+ assertEquals(143, minCost(new int[][]{{12, 1, 19},
+ {15, 1, 10},
+ {3, 11, 10},
+ {9, 3, 10},
+ {4, 8, 7},
+ {4, 18, 2},
+ {16, 6, 6},
+ {3, 3, 6},
+ {10, 18, 16},
+ {5, 4, 8},
+ {5, 3, 16},
+ {11, 8, 19},
+ {18, 15, 18},
+ {16, 4, 15},
+ {10, 7, 13},
+ {11, 10, 14},
+ {3, 9, 8},
+ {5, 2, 2},
+ {3, 2, 5},
+ {2, 19, 14},
+ {17, 3, 6},
+ {6, 4, 17},
+ {5, 15, 19},
+ {2, 14, 14},
+ {19, 4, 16}}));
+ }
+}
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