diff --git a/pom.xml b/pom.xml index 4ab34fe..30891ae 100644 --- a/pom.xml +++ b/pom.xml @@ -12,8 +12,8 @@ org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 11 + 11 @@ -39,7 +39,8 @@ org.projectlombok lombok - 1.16.8 + 1.18.12 + provided @@ -81,7 +82,7 @@ junit junit - 4.12 + 4.13.1 @@ -125,6 +126,25 @@ opencsv 4.0 + + + + org.hamcrest + hamcrest-library + 2.1 + test + + + org.apache.beam + beam-sdks-java-harness + 2.22.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.12.3 + + @@ -134,4 +154,4 @@ http://clojars.org/repo/ - \ No newline at end of file + diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/crackingCoding/IntEnglishV2.java b/src/main/java/com/eprogrammerz/examples/algorithm/crackingCoding/IntEnglishV2.java new file mode 100644 index 0000000..0034d5c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/crackingCoding/IntEnglishV2.java @@ -0,0 +1,64 @@ +package com.eprogrammerz.examples.algorithm.crackingCoding; + +import org.junit.Test; + +import java.util.TreeMap; + +import static org.junit.Assert.assertEquals; + +public class IntEnglishV2 { + private final static TreeMap DEFAULTS = new TreeMap<>(); + + static { + DEFAULTS.put(1, "One"); + DEFAULTS.put(2, "Two"); + DEFAULTS.put(3, "Three"); + DEFAULTS.put(4, "Four"); + DEFAULTS.put(5, "Five"); + DEFAULTS.put(6, "Six"); + DEFAULTS.put(7, "Seven"); + DEFAULTS.put(8, "Eight"); + DEFAULTS.put(9, "Nine"); + DEFAULTS.put(10, "Ten"); + DEFAULTS.put(11, "Eleven"); + DEFAULTS.put(12, "Twelve"); + DEFAULTS.put(13, "Thirteen"); + DEFAULTS.put(14, "Fourteen"); + DEFAULTS.put(15, "Fifteen"); + DEFAULTS.put(16, "Sixteen"); + DEFAULTS.put(17, "Seventeen"); + DEFAULTS.put(18, "Eighteen"); + DEFAULTS.put(19, "Nineteen"); + DEFAULTS.put(20, "Twenty"); + DEFAULTS.put(30, "Thirty"); + DEFAULTS.put(40, "Forty"); + DEFAULTS.put(50, "Fifty"); + DEFAULTS.put(60, "Sixty"); + DEFAULTS.put(70, "Seventy"); + DEFAULTS.put(80, "Eighty"); + DEFAULTS.put(90, "Ninety"); + DEFAULTS.put(100, "Hundred"); + DEFAULTS.put(1000, "Thousand"); + DEFAULTS.put(100000, "Million"); + } + + public String translate(int val) { + int floor = DEFAULTS.floorKey(val); + if (floor == val) { + return DEFAULTS.get(val); + } + int multiplier = val / floor; + return (val > 100 ? DEFAULTS.get(multiplier) + " " : "") + DEFAULTS.get(floor) + " " + translate(val - floor * multiplier); + } + + @Test + public void testMapIntToString() { + assertEquals("Twelve Thousand Three Hundred Forty Five", translate(12345)); + assertEquals("One Hundred Eleven", translate(111)); + assertEquals("Two Hundred Eleven", translate(211)); + assertEquals("One Hundred Twenty Four", translate(124)); + assertEquals("One Hundred Forty Four", translate(144)); + assertEquals("One Thousand One Hundred Twenty Four", translate(1124)); + assertEquals("Nine Thousand Two Hundred Twenty Four", translate(9224)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/Anadrome.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/Anadrome.java new file mode 100644 index 0000000..a153640 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/Anadrome.java @@ -0,0 +1,34 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Return number of character to be added to make a given string 'word' a anagram of palindrome. + */ +public class Anadrome { + public int changeToAnadrome(String word) { + int[] map = new int[128]; + int n = word.length(); + for (int i = 0; i < n; i++) { + map[word.charAt(i)]++; + } + + int odds = 0; + + for (int count: map) { + if (count % 2 != 0) odds++; + } + + if (odds == 0) return 0; + return odds - 1; + } + + @Test + public void test() { + assertEquals(1, changeToAnadrome("abcb")); + assertEquals(2, changeToAnadrome("abc")); + assertEquals(0, changeToAnadrome("tatoo")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/BinarySearchable.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/BinarySearchable.java new file mode 100644 index 0000000..ece8b14 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/BinarySearchable.java @@ -0,0 +1,74 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.*; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * Binary search is a search algorithm usually used on a sorted sequence to quickly find an element with a given value. + * In this problem we will evaluate how binary search performs on data that isn't necessarily sorted. An element is said to be binary searchable if, + * regardless of how the pivot is chosen the algorithm returns true. For example: + * + * [2, 1, 3, 4, 6, 5] and target = 5, we cannot find 5. Because when the pivot is 4, we get element 6, then right pointer will move left, + * so we'll lose the opportunity to find target 5. + * [2, 1, 3, 4, 5, 6] and target = 5, we can find 5. Because wherever we choose the pivots, we'll find target at last. + * Given an unsorted array of n distinct integers, return the number of elements that are binary searchable. + * + * Example 1: + * + * Input: [1, 3, 2] + * Output: 1 + * Explanation: However we choose the pivots, we will always find the number 1 when looking for it. This does not hold for 3 and 2. + * Example 2: + * + * Input: [2, 1, 3, 5, 4, 6] + * Output: 2 + * Explanation: 3 and 6 are the numbers guaranteed to be found. + * + * https://leetcode.com/discuss/interview-question/352743/ + */ +public class BinarySearchable { + public List binarySearchable(int[] arr) { + LinkedList l = new LinkedList<>(); + + int n = arr.length; + + if (n == 0) return l; + + // keep track of maximums while going left to right + // now traverse from right to left and see + // if curr <= right && curr >= leftMax[i] + // then that is searchable + + int[] leftMax = new int[n]; + leftMax[0] = arr[0]; + + for (int i = 1; i < n; i++) { + leftMax[i] = Math.max(arr[i], leftMax[i - 1]); + } + + int rightMin = Integer.MAX_VALUE; + for (int i = n - 1; i >= 0; i--) { + if (arr[i] <= rightMin && arr[i] >= leftMax[i]) { + l.addFirst(arr[i]); + } + rightMin = Math.min(rightMin, arr[i]); + } + + return l; + } + + @Test + public void test() { + assertThat(binarySearchable(new int[] {1,3,2}), is(Collections.singletonList(1))); + assertThat(binarySearchable(new int[] {2, 1, 3, 5, 4, 6}), is(asList(3, 6))); + assertThat(binarySearchable(new int[] {1, 5, 7, 11, 12, 18}), is(asList(1, 5, 7, 11, 12, 18))); + assertThat(binarySearchable(new int[] {3, 2, 1}), is(Collections.emptyList())); + assertThat(binarySearchable(new int[] {5, 4, 6, 2, 8}), is(Collections.singletonList(8))); + assertThat(binarySearchable(new int[] {1, 3, 2, 4, 5, 7, 6, 8}), is(asList(1, 4, 5, 8))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/DaysOfWeek.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/DaysOfWeek.java new file mode 100644 index 0000000..425faee --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/DaysOfWeek.java @@ -0,0 +1,27 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class DaysOfWeek { + private List daysInWeek = Arrays.asList("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"); + public String findNextDay(String day, int k) { + if (day == null) return null; + + int idx = daysInWeek.indexOf(day); + + return daysInWeek.get((idx + k) % 7); + } + + @Test + public void test() { + assertEquals("Fri", findNextDay("Wed", 2)); + assertEquals("Sat", findNextDay("Wed", 3)); + assertEquals("Sun", findNextDay("Wed", 4)); + assertEquals("Mon", findNextDay("Wed", 5)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/MatrixRotation.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/MatrixRotation.java index b91ffcd..1b2379f 100644 --- a/src/main/java/com/eprogrammerz/examples/algorithm/general/MatrixRotation.java +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/MatrixRotation.java @@ -1,20 +1,60 @@ package com.eprogrammerz.examples.algorithm.general; +import org.junit.Test; + /** * Created by 542596 on 3/5/2017. */ public class MatrixRotation { - public static void main(String[] args) { + + + /** + * You are given an n x n 2D matrix representing an image. + * + * Rotate the image by 90 degrees (clockwise). + * + * @param matrix + */ + public void rotateMatrix(int[][] matrix) { + int n = matrix.length; + for (int r = 0; r < n / 2; r++) { + for (int c = r; c < n - 1 - r; c++) { + int temp = matrix[r][c]; + // left to top + matrix[r][c] = matrix[n - 1 - c][r]; + // bottom to left + matrix[n - 1 - c][r] = matrix[n - 1 -r][n - 1 - c]; + // right to bottom + matrix[n - 1 - r][n - 1 - c] = matrix[c][n - 1 - r]; + // top to right + matrix[c][n - 1 - r] = temp; + } + } + } + + @Test + public void testRotateMatrix() { int[][] twoD = new int[][]{ /*{1,2}, {3,4}*/ - {1,2,3}, + /*{1,2,3}, {4,5,6}, - {7,8,9} + {7,8,9}*/ + {1,2,3,4}, + {6,7,8,9}, + {10,11,12,13}, + {14,15,16,17} }; - flipMatrix(twoD); - for(int i = 0; i< twoD.length; i++) { - for(int j = 0; j 2) return -1; + } else { + if (aCount == 2) { + aCount = 0; + } else if (aCount > 0) { + count += aCount; + aCount = 0; + } else { + count += 2; + aCount = 0; + } + } + } + if (str.charAt(str.length() - 1) != 'a') { + count += 2; + } else { + count += (2 - aCount); + } + return count; + } + + @Test + public void test() { + assertEquals(3, countMaxInsert("aabab")); + assertEquals(2, countMaxInsert("aababa")); + assertEquals(8, countMaxInsert("dog")); + assertEquals(0, countMaxInsert("aa")); + assertEquals(-1, countMaxInsert("baaaa")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/MaxNetworkRank.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/MaxNetworkRank.java new file mode 100644 index 0000000..3cb4263 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/MaxNetworkRank.java @@ -0,0 +1,42 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Find the max network rank in infrastructure where rank is total num of road connected to either cities + *

+ * Example + * A = [1,2,3,3] + * B = [2,3,1,4] + * N = 4 + *

+ * return 4 (city 2 and 3 with road [2,1], [2,3], [3,1], [3,4] + */ +public class MaxNetworkRank { + public int maxNetworkRank(int[] A, int[] B, int n) { + // map to store city - ranks + int[] ranks = new int[n]; + for (int i = 0; i < A.length; i++) { + int cityA = A[i]; + int cityB = B[i]; + ranks[cityA - 1]++; + ranks[cityB - 1]++; + } + + int max = 0; + + // traverse each city pair and sum their ranks and see it is max + for (int i = 0; i < A.length; i++) { + max = Math.max(ranks[A[i] - 1] + ranks[B[i] - 1] - 1, max); + } + return max; + } + + @Test + public void test() { + assertEquals(4, maxNetworkRank(new int[]{1, 2, 3, 3}, new int[]{2, 3, 1, 4}, 4)); + assertEquals(5, maxNetworkRank(new int[]{1, 2, 3, 3, 3}, new int[]{2, 3, 1, 4, 5}, 5)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/MaxPossibleValue.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/MaxPossibleValue.java new file mode 100644 index 0000000..2e8b467 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/MaxPossibleValue.java @@ -0,0 +1,63 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertEquals; + +/** + * return max possible value of n by inserting 5 + * + * for example: 0 -> 50 + * 2345 -> 52345 + * -99 -> -599 + * -23 -> -235 + */ +public class MaxPossibleValue { + public int maxPossibleValue(int n) { + if (n == 0) return 50; + if (n < 0) return (-1) * findValue(-n, false); + return findValue(n, true); + } + + private int findValue(int n, boolean isMax) { + Stack stack = new Stack<>(); + while (n != 0) { + stack.push(n % 10); + n /= 10; + } + + int num = 0; + boolean added = false; + while (!stack.isEmpty()) { + int digit = stack.pop(); + if (!added) { + if (isMax && digit <= 5) { + num = num * 10 + 5; + added = true; + } + + if (!isMax && digit > 5) { + num = num * 10 + 5; + added = true; + } + } + num = num * 10 + digit; + } + + if (!added) num = num * 10 + 5; + + return num; + } + + @Test + public void test() { + assertEquals(5268, maxPossibleValue(268)); + assertEquals(50, maxPossibleValue(0)); + assertEquals(550, maxPossibleValue(50)); + assertEquals(6750, maxPossibleValue(670)); + assertEquals(9995, maxPossibleValue(999)); + assertEquals(-5999, maxPossibleValue(-999)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/MergeSortList.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/MergeSortList.java new file mode 100644 index 0000000..a973935 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/MergeSortList.java @@ -0,0 +1,53 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertThat; +import static org.hamcrest.core.Is.is; + +/** + * Merge sort + */ +public class MergeSortList { + public void sort(List l) { + if (l == null || l.size() == 1) return; + int mid = l.size() / 2; + List left = new ArrayList<>(l.subList(0, mid)); + List right = new ArrayList<>(l.subList(mid, l.size())); + + sort(left); + sort(right); + merge(left, right, l); + } + + private void merge(List left, List right, List list) { + int leftIndex = 0; + int rightIndex = 0; + int listIndex = 0; + + while (leftIndex < left.size() && rightIndex < right.size()) { + if (left.get(leftIndex) < right.get(rightIndex)) { + list.set(listIndex++, left.get(leftIndex++)); + } else { + list.set(listIndex++, right.get(rightIndex++)); + } + } + while (leftIndex < left.size()) { + list.set(listIndex++, left.get(leftIndex++)); + } + while (rightIndex < right.size()) { + list.set(listIndex++, right.get(rightIndex++)); + } + } + + @Test + public void test1() { + List actual = Arrays.asList(1,4,3,2,7,5,6,8); + sort(actual); + assertThat(actual, is(Arrays.asList(1,2,3,4,5,6,7,8))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/NumWithEqualDigitSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/NumWithEqualDigitSum.java new file mode 100644 index 0000000..651b448 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/NumWithEqualDigitSum.java @@ -0,0 +1,69 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * given an array of integers, return max sum of pair whose digits sums to equals + */ +public class NumWithEqualDigitSum { + public int findMaxSum(int[] nums) { + Map> nList = new HashMap<>(); + for (int n: nums) { + int sum = findDigitSum(n); + List list = nList.get(sum); + if (list == null) { + list = new ArrayList<>(); + list.add(n); + nList.put(sum, list); + } else { + list.add(n); + } + } + + int maxSum = Integer.MIN_VALUE; + for (int key: nList.keySet()) { + List list = nList.get(key); + if (list.size() >= 2) { + int sum = list.size() == 2 ? list.get(0) + list.get(1) : findMaxSum(list); + if (sum > maxSum) maxSum = sum; + } + } + return maxSum == Integer.MIN_VALUE ? -1 : maxSum; + } + + private int findMaxSum(List l) { + int maxSum = Integer.MIN_VALUE; + for (int i = 0; i < l.size() - 1; i++) { + for (int j = i + 1; j < l.size(); j++) { + int sum = l.get(i) + l.get(j); + if (sum > maxSum) { + maxSum = sum; + } + } + } + return maxSum; + } + + private int findDigitSum(int n) { + int sum = 0; + while (n != 0) { + sum += n % 10; + n /= 10; + } + return sum; + } + + @Test + public void test() { + assertEquals(93, findMaxSum(new int[] {51, 17, 71, 42})); + assertEquals(102, findMaxSum(new int[] {42, 33, 60})); + assertEquals(-1, findMaxSum(new int[] {51, 32, 43})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/PrintFractions.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/PrintFractions.java new file mode 100644 index 0000000..80d328b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/PrintFractions.java @@ -0,0 +1,69 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +/** + * Print all the fractions from 0 to 1 with N being the highest denominator. The fractions must be printed in order. + * If duplicate fraction values are found, then print the fraction in the lowest form. For example, If you have 1/2 and 5/10, then only 1/2 would printed. + * + * Example + * + * Input: n = 4 + * Output: ["0/1", "1/4", "1/3", "1/2", "2/3", "3/4", "1/1"] + */ +public class PrintFractions { + /** + * Time O(n^2) + * Space O(1) + * + * @param n + * @return + */ + public List fractions(int n) { + List l = new ArrayList<>(); + + if (n == 0) return l; + + List pairs = new ArrayList<>(); + + for (int den = 1; den <= n; den++) { + for (int num = 1; num <= den; num++) { + if (gcd(den, num) == 1) { + pairs.add(new int[] {num, den}); + } + } + } + + // O(k * logk) + pairs.sort((p1, p2) -> p1[0] * p2[1] - p1[1] * p2[0]); + + l.add("0/1"); + for (int[] pair: pairs) { + l.add(String.format("%d/%d", pair[0], pair[1])); + } + return l; + } + + private int gcd(int a, int b) { +// if (b == 0) return a; +// return gcd(b, a % b); + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + + return a; + } + + @Test + public void test() { + assertEquals(asList("0/1", "1/4", "1/3", "1/2", "2/3", "3/4", "1/1"), fractions(4)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/ProductCategoryTest.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/ProductCategoryTest.java new file mode 100644 index 0000000..f653320 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/ProductCategoryTest.java @@ -0,0 +1,133 @@ +package com.eprogrammerz.examples.algorithm.general; + +import lombok.AllArgsConstructor; +import lombok.Data; +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +class ProductService { + List findByCategory(List products, String categoryName) { + if (categoryProducts == null) { + createCategoryProductsMap(products); + } + List cProducts = categoryProducts.get(categoryName); + + List result = new ArrayList<>(); + + if (cProducts == null || cProducts.isEmpty()) return result; + + result.addAll(cProducts); + + for (Product product: cProducts) { + List subCategories = product.getCategory().getSubCategories(); + if (subCategories != null) { + for (Category c : subCategories) { + List subProducts = findByCategory(products, c.getName()); + result.addAll(subProducts); + } + } + } + + return result; + } + + private void createCategoryProductsMap(List products) { + this.categoryProducts = new HashMap<>(); + + for (Product product: products) { + Category category = product.getCategory(); + + if (!this.categoryProducts.containsKey(category.getName())) { + this.categoryProducts.put(category.getName(), new ArrayList<>()); + } + List existing = this.categoryProducts.get(category.getName()); + + existing.add(product); + } + + } + + private Map> categoryProducts = null; +} + +public class ProductCategoryTest { + + + /** + * Category + * | + * ------------------------------------------ + * | | | + * Sports Electronics Apparel + * | | | + * ---------------------- --------------- ----------------------------- + * | | | | | | | + * Jersey Footware TV Phone Shirts Pants Athletic + * | + * ------------------------ + * | | + * Yoga Outdoor + */ + @Test + public void testProductsByCategory() { + Category jersey = new Category(10, "Jersey", null); + Category footware = new Category(11, "Footware", null); + Category sports = new Category(1, "Sports", Arrays.asList(jersey, footware)); + + Category tv = new Category(12, "TV", null); + Category phone = new Category(13, "Phone", null); + Category electronics = new Category(3, "Electronics", Arrays.asList(tv, phone)); + + + Category shirts = new Category(14, "Shirts", null); + Category pants = new Category(15, "Panys", null); + Category yoga = new Category(20, "Yoga", null); + Category outdoor = new Category(21, "Outdoor", null); + Category athletic = new Category(16, "Athletic", Arrays.asList(yoga, outdoor)); + Category apparel = new Category(2, "Apparel", Arrays.asList(shirts, pants, athletic)); + + Product p1 = new Product(1, "Nike Air Max 97", sports); + Product p2 = new Product(2, "Nike T-Shirt", apparel); + Product p3 = new Product(3, "Jordon 97", sports); + Product p4 = new Product(4, "Iphone 97", electronics); + Product p5 = new Product(5, "Samsung Washer and Dryer", electronics); + Product pJersey = new Product(6, "Barcelan", jersey); + Product pFootware = new Product(7, "Nike Air", footware); + Product luluman = new Product(8, "Yoga Pants", yoga); + + List products = Arrays.asList(p1, p2, p3, p4, p5, pJersey, pFootware, luluman); + + + ProductService pc = new ProductService(); + + List apparels = pc.findByCategory(products, apparel.getName()); + System.out.println(apparels); + assertEquals(1, apparels.size()); + + List sportsProducts = pc.findByCategory(products, sports.getName()); + System.out.println(sportsProducts); + + assertEquals(4, sportsProducts.size()); + } +} + + +@Data +@AllArgsConstructor +class Product { + private int id; + private String name; + private Category category; +} + +@Data +@AllArgsConstructor +class Category { + private int id; + private String name; + + List subCategories; +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/ShoppingCartTest.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/ShoppingCartTest.java new file mode 100644 index 0000000..ff467af --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/ShoppingCartTest.java @@ -0,0 +1,149 @@ +package com.eprogrammerz.examples.algorithm.general; + +import com.google.common.collect.Sets; +import lombok.EqualsAndHashCode; +import org.junit.Test; + +import java.util.*; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class ShoppingCartTest { + + @Test + public void test() { + ShoppingCart cart = new ShoppingCart(); + cart.addOffer(1, 100, 300); + cart.addOffer(1, 200, 450); + cart.addOffer(2, 300, 50); + + // offer close to lower bound + Set offers1 = Sets.newHashSet(new Offer(1, 100, 300)); + assertThat(cart.getClosestOffer(1, 200), is(offers1)); + + Set offers2 = Sets.newHashSet(new Offer(1, 200, 450)); + assertThat(cart.getClosestOffer(1, 500), is(offers2)); + + // remove offer + cart.removeOffer(200); + + // the query should return the lower bound + assertThat(cart.getClosestOffer(1, 500), is(offers1)); + } + +} + +/** + * Assume a Google Shopping cart application. There are multiple products being sold, each product is sold by multiple vendors each having their own offer with a price. + * so each product can have multiple offers. + *

+ * There are three entities prodcutID, offerID, and Price. + *

+ * Implement these three methods in the most efficient manner : + *

+ * public class ShoppingCart { + *

+ * public void addOffer(long productID, long offerID, double price) { + * } + *

+ * public void removeOffer(long offerID) { + * } + *

+ * public long getClosestOffer(long productID, double price) { + * } + *

+ * } + * P1 - O1 - $300 + * P1 - O2 - $450 + * P2 - O3 - $50 + *

+ * getClosestOffer(P1, 250) -> O1 + * getClosestOffer(P1, 500) -> O2 + *

+ * return the offer which is closest to a given price. + *

+ * Assume there is no memory restriction. + */ +class ShoppingCart { + private Map>> store = new HashMap<>(); + private Map offers = new HashMap<>(); + + /** + * Creates new entry for given product id and offers associated if not existed before + * else updated offers with new offer for that particular product + *

+ * Time: O(logm) - for one product, m = no. of offers for particular product + * O(n*logm) - for n products + * + * @param productID + * @param offerID + * @param price + */ + public void addOffer(long productID, long offerID, double price) { + Offer offer = new Offer(productID, offerID, price); + + store.computeIfAbsent(productID, s -> new TreeMap<>()); + + store.get(productID).computeIfAbsent(price, s -> new HashSet<>()); + + store.get(productID).get(price).add(offer); + + offers.put(offerID, offer); + } + + // Time O(logm) for one + // O(n * logm) for n + public void removeOffer(long offerID) { + if (offers.containsKey(offerID)) { + Offer offer = offers.remove(offerID); + + TreeMap> map = store.get(offer.productId); + + map.get(offer.price).remove(offer); + + if (map.get(offer.price).isEmpty()) { + map.remove(offer.price); + } + } + } + + // Time O(logm) + public Set getClosestOffer(long productID, double price) { + TreeMap> map = store.get(productID); + + if (offers == null) return null; + + Double smaller = map.floorKey(price); + Double larger = map.ceilingKey(price); + + if (smaller == null && larger == null) return null; + + if (smaller != null && larger != null) { + double d1 = price - smaller; + double d2 = larger - price; + + double close = d1 < d2 ? smaller : larger; + + return map.get(close); + } + + if (smaller == null) return map.get(larger); + else return map.get(smaller); + } + + +} + +@EqualsAndHashCode +class Offer { + long productId; + long offerId; + double price; + + Offer(long productId, long offerId, double price) { + this.productId = productId; + this.offerId = offerId; + this.price = price; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/StudentPriorityQueue.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/StudentPriorityQueue.java new file mode 100644 index 0000000..47cdc52 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/StudentPriorityQueue.java @@ -0,0 +1,98 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.Assert.assertEquals; + +/** + * Find order in which student can be served! + * Criterion: + * 1. Highest GPA first + * 2. If same gpa, alphabetic order + * 3. If same name, id ascending + */ + +public class StudentPriorityQueue { + @Test + public void testGetStudents() { + Priorities priorities = new Priorities(); + + List events = Arrays.asList( + "ENTER John 3.75 50", + "ENTER Mark 3.8 24", + "ENTER Shafaet 3.7 35", + "SERVED", + "SERVED", + "ENTER Samiha 3.85 36", + "SERVED", + "ENTER Ashley 3.9 42", + "ENTER Maria 3.6 46", + "ENTER Anik 3.95 49", + "ENTER Dan 3.95 50", + "SERVED"); + List toBeServed = Arrays.asList("Dan", "Ashley", "Shafaet", "Maria"); + assertEquals(toBeServed, priorities.getStudents(events).stream().map(Student::getName).collect(Collectors.toList())); + } +} + +class Student { + private int id; + private String name; + private double cgpa; + + Student(int id, String name, double cgpa) { + this.id = id; + this.name = name; + this.cgpa = cgpa; + } + + public int getId() { + return this.id; + } + + public String getName() { + return this.name; + } + + public double getCGPA() { + return this.cgpa; + } +} + +class Priorities { + List getStudents(List events) { + Comparator c = (s1, s2) -> { + double diff = s2.getCGPA() - s1.getCGPA(); + if (diff > 0) { + return 1; + } else if (diff < 0) { + return -1; + } + int nameComp = s1.getName().compareTo(s2.getName()); + if (nameComp == 0) return s1.getId() - s2.getId(); + + return nameComp; + }; + Queue queue = new PriorityQueue<>(c); + for (String event : events) { + if (event.startsWith("ENTER")) { + String[] parts = event.split(" "); + String name = parts[1]; + double cgpa = Double.valueOf(parts[2]); + int id = Integer.valueOf(parts[3]); + queue.add(new Student(id, name, cgpa)); + } else { + queue.poll(); + } + } + + List result = new ArrayList<>(); + while (!queue.isEmpty()){ + result.add(queue.poll()); + } + return result; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/UglyNumberII.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/UglyNumberII.java new file mode 100644 index 0000000..04bb172 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/UglyNumberII.java @@ -0,0 +1,53 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; +import java.util.PriorityQueue; + +import static org.junit.Assert.assertEquals; + +/** + * Write a program to find the n-th ugly number. + *

+ * Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. + *

+ * Example: + *

+ * Input: n = 10 + * Output: 12 + * Explanation: 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers + */ +public class UglyNumberII { + private List factors = Arrays.asList(2L, 3L, 5L); + + public int nthUglyNumber(int n) { + if (n <= 3) return n; + + PriorityQueue pq = new PriorityQueue<>(factors); + + + int count = 1; + long ugly = 1; + while (count < n) { + ugly = pq.poll(); + + if (ugly != pq.peek()) { + count++; + + for (long factor : factors) { + pq.add(factor * ugly); + } + } + } + + return (int) ugly; + } + + @Test + public void test1() { + int ugly = nthUglyNumber(10); + assertEquals(12, ugly); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/UniqueElementInSubArr.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/UniqueElementInSubArr.java new file mode 100644 index 0000000..59ddb4f --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/UniqueElementInSubArr.java @@ -0,0 +1,70 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * you are given N integers. You need to find the maximum number of unique integers among all the possible contiguous subarrays of size M. + * + * Sample Input + * + * 6 3 + * 5 3 5 2 3 2 + * Sample Output + * + * 3 + * + */ +public class UniqueElementInSubArr { + + public int maxElementSubArr(int[] arr, int m) { + // deque so that element can be removed from first and added at last + Deque deque = new ArrayDeque<>(); + + // map to track elem count + Map map = new HashMap<>(); + + int res = 0; + + for (int elem : arr) { + deque.addLast(elem); + + if (map.containsKey(elem)) { + map.put(elem, map.get(elem) + 1); + } else { + map.put(elem, 1); + } + + // if we get to the window size, then need to adjust list and map + if (deque.size() == m) { + if (map.size() > res) { + res = map.size(); + } + int head = deque.removeFirst(); + int newCount = map.get(head) - 1; + if (newCount == 0) { + map.remove(head); + } else { + map.put(head, newCount); + } + } + } + + return res; + } + + @Test + public void testMaxElementSubArr() { + int[] input1 = new int[] {5, 3, 5, 2, 3, 2}; + assertEquals(3, maxElementSubArr(input1, 3)); + + int[] input2 = new int[] {1, 2, 3}; + assertEquals(3, maxElementSubArr(input2, 3)); + + int[] input3 = new int[] {1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; + assertEquals(1, maxElementSubArr(input3, 3)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/general/ZeroMover.java b/src/main/java/com/eprogrammerz/examples/algorithm/general/ZeroMover.java new file mode 100644 index 0000000..a7b896b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/general/ZeroMover.java @@ -0,0 +1,42 @@ +package com.eprogrammerz.examples.algorithm.general; + +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; + +/** + * move all the zeros to the end of the array + * [1,0,2,0,9] -> [1,2,9,0,0] + */ +public class ZeroMover { + public void moveZerosToEnd(int[] input) { + int zeroIdx = 0; + int nonZeroIdx = 0; + + while (zeroIdx < input.length && nonZeroIdx < input.length) { + if (input[zeroIdx] == 0) { + if (zeroIdx < nonZeroIdx && input[nonZeroIdx] != 0) { + swap(input, zeroIdx, nonZeroIdx); + } else { + nonZeroIdx++; + } + } else { + zeroIdx++; + nonZeroIdx++; + } + } + } + + public void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + @Test + public void test() { + int[] input = new int[] {1,0,2,0,9}; + moveZerosToEnd(input); + assertArrayEquals(new int[] {1,2,9,0,0}, input); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/CheapestFlightWKStops.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/CheapestFlightWKStops.java new file mode 100644 index 0000000..3ebf891 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/CheapestFlightWKStops.java @@ -0,0 +1,54 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/cheapest-flights-within-k-stops/ + */ +public class CheapestFlightWKStops { + // Dijkstra's algorithm + public int findCheapestPrice(int n, int[][] flights, int src, int dst, int K) { + // create adj list to represent graph + List[] graph = new ArrayList[n]; + for (int i = 0; i < n; i++) { + graph[i] = new ArrayList<>(); + } + + for (int[] flight: flights) { + int u = flight[0]; + int v = flight[1]; + int cost = flight[2]; + graph[u].add(new int[] {v, cost}); + } + + // to track which cities has been visited + PriorityQueue q = new PriorityQueue<>((e1, e2) -> e1[1] - e2[1]); + q.add(new int[] {src, 0, K}); + + while (!q.isEmpty()) { + int[] city = q.poll(); + + if (city[0] == dst) { + return city[1]; + } + + if (city[2] >= 0) { + for (int[] neigbhor: graph[city[0]]) { + q.add(new int[] {neigbhor[0], city[1] + neigbhor[1], city[2] - 1}); + } + } + } + return -1; + } + + @Test + public void test() { + assertEquals(200, findCheapestPrice(3, new int[][] {{0,1,100}, {1,2,100}, {0,2,500}}, 0, 2, 1)); + assertEquals(500, findCheapestPrice(3, new int[][] {{0,1,100}, {1,2,100}, {0,2,500}}, 0, 2, 0)); + assertEquals(6, findCheapestPrice(4, new int[][] {{0,1,1},{0,2,5},{1,2,1},{2,3,1}}, 0, 3, 1)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/CriticalConnection.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/CriticalConnection.java new file mode 100644 index 0000000..0453740 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/CriticalConnection.java @@ -0,0 +1,87 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static java.util.Arrays.asList; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/critical-connections-in-a-network/ + * + * Tarjen's algorithm + * + * https://www.youtube.com/watch?v=CsGP_s_3GWg&list=PLdo5W4Nhv31bK5n8-RIGhvYs8bJbgJFDR&index=13&t=543s + */ +public class CriticalConnection { + private int d = 0; + public List> criticalConnections(int n, List> connections) { + List> res = new ArrayList<>(); + + List[] graph = new ArrayList[n]; + + for (int i = 0; i < n; i++) { + graph[i] = new ArrayList<>(); + } + + for (List edge: connections) { + int u = edge.get(0); + int v = edge.get(1); + + graph[u].add(v); + graph[v].add(u); + } + + int[] visitTime = new int[n]; + + boolean[] visited = new boolean[n]; + + dfs(0, graph, visited, visitTime, res); + + return res; + } + + private void dfs(int u, List[] graph, boolean[] visited, int[] visitTime, List> res) { + if (visited[u]) return; + + visited[u] = true; + + visitTime[u] = d; + d++; + + for (int v: graph[u]) { + if (!visited[v]) { + + dfs(v, graph, visited, visitTime, res); + + visitTime[v] = lowestVisitedTime(graph, u, v, visitTime); + + if (visitTime[v] > visitTime[u]) { + res.add(asList(u, v)); + } + } + } + } + + private int lowestVisitedTime(List[] graph, int u, int v, int[] visitTime) { + int min = visitTime[v]; + + for (int n: graph[v]) { + if (n != u) { + min = Math.min(visitTime[n], min); + } + } + + return min; + } + + @Test + public void test() { + assertThat(criticalConnections(4, asList(asList(0,1), asList(1,2), asList(2,0), asList(1,3))), is(asList(asList(1,3)))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/FloweringPlants.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/FloweringPlants.java new file mode 100644 index 0000000..07718a3 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/FloweringPlants.java @@ -0,0 +1,116 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertArrayEquals; + + +/** + * You have N gardens, labelled 1 to N. In each garden, you want to plant one of 4 types of flowers. + * + * paths[i] = [x, y] describes the existence of a bidirectional path from garden x to garden y. + * + * Also, there is no garden that has more than 3 paths coming into or leaving it. + * + * Your task is to choose a flower type for each garden such that, for any two gardens connected by a path, they have different types of flowers. + * + * Return any such a choice as an array answer, where answer[i] is the type of flower planted in the (i+1)-th garden. + * The flower types are denoted 1, 2, 3, or 4. It is guaranteed an answer exists. + * + * + * + * Example 1: + * + * Input: N = 3, paths = [[1,2],[2,3],[3,1]] + * Output: [1,2,3] + */ +public class FloweringPlants { + public int[] gardenNoAdj(int N, int[][] paths) { + // 1 --- 2 + // | | + // --3-- + + // adjacency matrix + // 1 - [2,3] + // 2 - [1,3] + // 3 - [1,2] + + // 1 - 1 + // 2 - 2 + int[] colors = new int[N]; + + Arrays.fill(colors, 1); + + Map> gardens = new HashMap<>(); + + for (int[] path : paths) { + List neighbors = gardens.get(path[0]); + if (neighbors == null) { + neighbors = new ArrayList<>(); + } + neighbors.add(path[1]); + gardens.put(path[0], neighbors); + + neighbors = gardens.get(path[1]); + if (neighbors == null) { + neighbors = new ArrayList<>(); + } + neighbors.add(path[0]); + gardens.put(path[1], neighbors); + } + + for (int garden : gardens.keySet()) { + List neighbors = gardens.get(garden); + + int[] gone = new int[5]; + for (int n : neighbors) { + if (colors[n - 1] != -1) { + gone[colors[n - 1]] = colors[n - 1]; + } + } + + int color = 1; + + for (int i = 1; i <= 5; i++) { + if (gone[i] != i) { + color = i; + break; + } + } + colors[garden - 1] = color; + } + return colors; + } + + @Test + public void test1() { + int[] expected = new int[]{2, 3, 1}; + int[][] paths = new int[][]{ + {1, 2}, + {2, 3}, + {3, 1} + }; + assertArrayEquals(expected, gardenNoAdj(3, paths)); + } + + @Test + public void test2() { + int[] expected = new int[]{2, 1, 2, 1}; + int[][] paths = new int[][]{ + {1, 2}, + {3, 4} + }; + assertArrayEquals(expected, gardenNoAdj(4, paths)); + } + + @Test + public void test3() { + int[] expected = new int[]{2, 3, 4, 1}; + int[][] paths = new int[][]{ + {1, 2}, {2, 3}, {3, 4}, {4, 1}, {1, 3}, {2, 4} + }; + assertArrayEquals(expected, gardenNoAdj(4, paths)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/LargestComponent.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/LargestComponent.java new file mode 100644 index 0000000..5bbd4b4 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/LargestComponent.java @@ -0,0 +1,58 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/largest-component-size-by-common-factor/ + */ +public class LargestComponent { + public int largestComponentSize(int[] A) { + int[] parents = new int[100001]; + + for (int i = 0; i < parents.length; i++) { + parents[i] = i; + } + + + for (int a: A) { + for (int j = (int) Math.sqrt(a); j >= 2; j--) { + union(parents, a, j); + union(parents, a, a / j); + } + } + + Map countMap = new HashMap<>(); + + int max = 0; + + for (int a: A) { + int k = root(parents, a); + int curr = countMap.getOrDefault(k, 0) + 1; + if (curr > max) max = curr; + countMap.put(k, curr); + } + + return max; + } + + private int root(int[] parents, int u) { + while (u != parents[u]) { + u = parents[u]; + } + return u; + } + + private void union(int[] parents, int u, int v) { + + parents[root(parents, v)] = parents[root(parents, u)]; + } + + @Test + public void test() { + assertEquals(8, largestComponentSize(new int[] {2,3,6,7,4,12,21,39})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/MakeNetworkConnected.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/MakeNetworkConnected.java new file mode 100644 index 0000000..aa584e6 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/MakeNetworkConnected.java @@ -0,0 +1,65 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/number-of-operations-to-make-network-connected/ + */ +public class MakeNetworkConnected { + public int makeConnected(int n, int[][] connections) { + int extra = 0; + + int[] parents = new int[n]; + for (int i = 0; i < n; i++) parents[i] = i; + + for (int[] con: connections) { + int u = con[0]; + int v = con[1]; + + if (root(parents, u) != root(parents, v)) { + union(parents, u, v); + } else { + extra++; + } + } + + Set set = new HashSet<>(); + for (int p: parents) { + set.add(root(parents, p)); + } + + int comp = set.size(); + + if (comp - extra <= 1) return comp - extra == 1 ? extra: comp - 1; + + return -1; + } + + private void union(int[] parents, int u, int v) { + parents[root(parents, v)] = parents[root(parents, u)]; + } + + private int root(int[] parents, int u) { + while (u != parents[u]) { + u = parents[u]; + } + return u; + } + + @Test + public void test1() { + int[][] connections = new int[][] {{0,1},{0,2},{0,3},{1,2},{1,3}}; + assertEquals(2, makeConnected(6, connections)); + } + + @Test + public void test2() { + int[][] connections = new int[][] {{0,1},{0,2},{3,4},{2,3}}; + assertEquals(0, makeConnected(5, connections)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/NetworkDelayTime.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/NetworkDelayTime.java new file mode 100644 index 0000000..7898795 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/NetworkDelayTime.java @@ -0,0 +1,68 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.PriorityQueue; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/network-delay-time/ + */ +public class NetworkDelayTime { + public int networkDelayTime(int[][] times, int N, int K) { + List[] graph = new ArrayList[N + 1]; + for (int i = 0; i <= N; i++) { + graph[i] = new ArrayList<>(); + } + + for(int[] time: times) { + int u = time[0]; + int v = time[1]; + int w = time[2]; + + graph[u].add(new int[] {v, w}); + } + + PriorityQueue pq = new PriorityQueue<>((e1, e2) -> e1[1] - e2[1]); + pq.offer(new int[] {K, 0}); + + int[] dist = new int[N + 1]; + Arrays.fill(dist, Integer.MAX_VALUE); + dist[K] = 0; + dist[0] = 0; + while (!pq.isEmpty()) { + int[] curr = pq.poll(); + dist[curr[0]] = Math.min(curr[1], dist[curr[0]]); + + for (int[] neighbor: graph[curr[0]]) { + if (dist[neighbor[0]] == Integer.MAX_VALUE) { + pq.add(new int[] {neighbor[0], neighbor[1] + curr[1]}); + } else if (neighbor[1] + curr[1] < dist[neighbor[0]]) { + pq.add(new int[] {neighbor[0], neighbor[1] + curr[1]}); + } + + } + } + + int max = Integer.MIN_VALUE; + + for (int d: dist) { + if (d > max) { + max = d; + } + + if (d == Integer.MAX_VALUE) return -1; // this node never reached + } + + return max; + } + + @Test + public void test() { + assertEquals(2, networkDelayTime(new int[][] {{2,1,1},{2,3,1},{3,4,1}}, 4, 2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/RedundantConnection.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/RedundantConnection.java new file mode 100644 index 0000000..41919c0 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/RedundantConnection.java @@ -0,0 +1,62 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; + +/** + * https://leetcode.com/problems/redundant-connection/ + */ +public class RedundantConnection { + /** + * Kruskal's algorithm implementation + * + * + * @param edges + * @return + */ + public int[] findRedundantConnection(int[][] edges) { + // spanning tree + int[] A = new int[edges.length + 1]; + // initialize + for (int i = 0; i < A.length; i++) { + A[i] = i; + } + int[] res = new int[2]; + for (int[] edge : edges) { + int start = edge[0]; + int end = edge[1]; + if (root(A, start) != root(A, end)) { // if two vertices have different root, then connect them with edge + union(A, start, end); + } else { // else, it is redundant + res[0] = start; + res[1] = end; + } + } + return res; + } + + private int root(int[] A, int v) { + while (v != A[v]) { + v = A[v]; + } + return v; + } + + private void union(int[] A, int u, int v) { + A[root(A, v)] = A[root(A, u)]; + } + + @Test + public void test() { + /** + * Input: [[1,2], [2,3], [3,4], [1,4], [1,5]] + * Output: [1,4] + * Explanation: The given undirected graph will be like this: + * 5 - 1 - 2 + * | | + * 4 - 3 + */ + assertArrayEquals(new int[]{1, 4}, findRedundantConnection(new int[][]{{1, 2}, {2, 3}, {3, 4}, {1, 4}, {1, 5}})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/SimilarStringGroups.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/SimilarStringGroups.java new file mode 100644 index 0000000..ebbf157 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/SimilarStringGroups.java @@ -0,0 +1,74 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/similar-string-groups/ + */ +public class SimilarStringGroups { + public int numSimilarGroups(String[] A) { + Map> graph = new HashMap<>(); + + for (String v: A) { + graph.put(v, new ArrayList<>()); + } + + for (int i = 0; i < A.length; i++) { + String u = A[i]; + + List uNeighbors = graph.get(u); + + for (int j = i + 1; j < A.length; j++) { + String v = A[j]; + List vNeighbors = graph.get(v); + + if (edge(u, v)) { + uNeighbors.add(v); + vNeighbors.add(u); + } + } + } + + Set visited = new HashSet<>(); + + int count = 0; + + for (String v: A) { + if (!visited.contains(v)) { + count++; + dfs(visited, graph, v); + } + } + + return count; + } + + private boolean edge(String u, String v) { + int diff = 0; + + for (int i = 0; i < u.length(); i++) { + if (u.charAt(i) != v.charAt(i)) diff++; + } + return diff == 2; + } + + private void dfs(Set visited, Map> graph, String v) { + if (visited.contains(v)) return; + visited.add(v); + + List neighbors = graph.get(v); + + for (String n: neighbors) { + dfs(visited, graph, n); + } + } + + @Test + public void test() { + assertEquals(2, numSimilarGroups(new String[] {"tars", "star", "arts", "rats"})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/graphs/TwoDSearchBoard.java b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/TwoDSearchBoard.java new file mode 100644 index 0000000..ee7a6d2 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/graphs/TwoDSearchBoard.java @@ -0,0 +1,80 @@ +package com.eprogrammerz.examples.algorithm.graphs; + +import org.junit.Test; + +import java.util.*; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/word-search-ii/ + */ +public class TwoDSearchBoard { + public List findWords(char[][] board, String[] words) { + List[] map = new ArrayList[26]; + + for (String word : words) { + int key = word.charAt(0) - 'a'; + + if (map[key] == null) { + map[key] = new ArrayList<>(); + } + map[key].add(word); + } + + int m = board.length; + int n = board[0].length; + + Set found = new HashSet<>(); + + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + char curr = board[r][c]; + if (map[curr - 'a'] != null) { + List candidates = map[curr - 'a']; + + for (String candidate : candidates) { + if (found.contains(candidate)) continue; + + if (dfs(board, candidate, 0, r, c)) { + found.add(candidate); + } + } + } + } + } + return new ArrayList<>(found); + + } + + private boolean dfs(char[][] board, String word, int idx, int r, int c) { + + if (r < 0 || r >= board.length || c < 0 || c >= board[0].length || board[r][c] != word.charAt(idx)) return false; + + if (idx == word.length() - 1) return true; + + board[r][c] = '0'; + + boolean val = dfs(board, word, idx + 1, r - 1, c) || + dfs(board, word, idx + 1, r + 1, c) || + dfs(board, word, idx + 1, r, c + 1) || + dfs(board, word, idx + 1, r, c - 1); + + board[r][c] = word.charAt(idx); + + return val; + } + + @Test + public void test() { + char[][] board = { + {'o', 'a', 'a', 'n'}, + {'e', 't', 'a', 'e'}, + {'i', 'h', 'k', 'r'}, + {'i', 'f', 'l', 'v'} + }; + List actual = findWords(board, new String[]{"oath", "pea", "eat", "rain"}); + assertThat(actual, hasItems("oath", "eat")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AddStrings.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AddStrings.java new file mode 100644 index 0000000..73688df --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AddStrings.java @@ -0,0 +1,53 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class AddStrings { + /** + * Add numbers represented by strings + * 123 + 980 = 1103 + * @param num1 + * @param num2 + * @return + */ + public String addStrings(String num1, String num2) { + StringBuilder sb1 = new StringBuilder(num1).reverse(); + StringBuilder sb2 = new StringBuilder(num2).reverse(); + StringBuilder sb = new StringBuilder(); + + int n1 = 0; + int n2 = 0; + int carry = 0; + + + while (n1 < sb1.length() || n2 < sb2.length()) { + int x = n1 < sb1.length() ? sb1.charAt(n1) - 48 : 0; + int y = n2 < sb2.length() ? sb2.charAt(n2) - 48 : 0; + + int sum = x + y + carry; + + carry = sum / 10; + sum = sum % 10; + + sb.append(sum); + + n1++; + n2++; + } + + if (carry > 0) { + sb.append(carry); + } + + return sb.reverse().toString(); + } + + @Test + public void test() { + assertEquals("1110", addStrings("123", "987")); + assertEquals("218", addStrings("120", "98")); + assertEquals("107", addStrings("98", "9")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AlphabetBoardPath.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AlphabetBoardPath.java new file mode 100644 index 0000000..3494b10 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AlphabetBoardPath.java @@ -0,0 +1,80 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/alphabet-board-path/ + */ +public class AlphabetBoardPath { + public String alphabetBoardPath(String target) { + String[] board = {"abcde", "fghij", "klmno", "pqrst", "uvwxy", "z"}; + + StringBuilder sb = new StringBuilder(); + + int x = 0, y = 0; + + for (char ch: target.toCharArray()) { + Queue q = new LinkedList<>(); + q.add(new Pair(x, y, "")); + + Set visited = new HashSet<>(); + visited.add(x + "#" + y); + + while (!q.isEmpty()) { + Pair curr = q.poll(); + + x = curr.x; + y = curr.y; + + if (board[x].charAt(y) == ch) { + sb.append(curr.path).append('!'); + break; + } + + for (int i = 0; i < 4; i++) { + int nr = x + dr[i]; + int nc = y + dc[i]; + + String key = nr + "#" + nc; + if (nr >= 0 && nr < board.length && nc >= 0 && nc < board[nr].length() && + !visited.contains(key)) { + q.offer(new Pair(nr, nc, curr.path + dir[i])); + visited.add(key); + } + } + } + } + + return sb.toString(); + } + + private int[] dr = {-1,1,0,0}; + private int[] dc = {0,0,-1,1}; + + private char[] dir = {'U', 'D', 'L', 'R'}; + + class Pair { + int x; + int y; + String path; + + Pair(int x, int y, String path) { + this.x = x; + this.y = y; + this.path = path; + } + } + + @Test + public void test() { + assertEquals("DDR!UURRR!!DDD!", alphabetBoardPath("leet")); + assertEquals("RR!DDRR!UUL!R!", alphabetBoardPath("code")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AlphabetMapping.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AlphabetMapping.java new file mode 100644 index 0000000..b50f658 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AlphabetMapping.java @@ -0,0 +1,53 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/decrypt-string-from-alphabet-to-integer-mapping/ + */ +public class AlphabetMapping { + public String freqAlphabets(String s) { + int start = 0; + + + StringBuilder sb = new StringBuilder(); + + while (start < s.length()) { + + int val = 0; + int end = start; + for (; end < s.length(); end++) { + if (s.charAt(end) == '#' || val > 26) { + if (val <= 26) { + sb.append((char) (val - 1 + 'a')); + start = end + 1; + } else { + sb.append((char)(s.charAt(start) - '0' - 1 + 'a')); + start++; + } + break; + } + val = val * 10 + (s.charAt(end) - '0'); // val = 10 + } + + if (end == s.length() && s.charAt(end - 1) != '#') { + while (start < s.length()) { + sb.append((char)(s.charAt(start) - '0' - 1 + 'a')); + start++; + } + } + } + + return sb.toString(); + } + + @Test + public void test() { + assertEquals("jkab",freqAlphabets("10#11#12")); + assertEquals("jkl",freqAlphabets("10#11#12#")); + assertEquals("acz",freqAlphabets("1326#")); + assertEquals("abcdefghijklmnopqrstuvwxyz",freqAlphabets("12345678910#11#12#13#14#15#16#17#18#19#20#21#22#23#24#25#26#")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AmbiguousCoordinates.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AmbiguousCoordinates.java new file mode 100644 index 0000000..2c163d6 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/AmbiguousCoordinates.java @@ -0,0 +1,98 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * https://leetcode.com/problems/ambiguous-coordinates/ + */ +public class AmbiguousCoordinates { + public List ambiguousCoordinates(String S) { + List l = new ArrayList<>(); + String num = S.substring(1, S.length() - 1); + + for (int i = 1; i < num.length(); i++) { + // we try to put comma at each index + // and see if x and y are valid + String x = num.substring(0, i); + String y = num.substring(i); + + boolean validX = valid(x); + boolean validY = valid(y); + if (validX && validY) { + l.add("(" + x + ", " + y + ")"); + } + + for (int j = 1; j < x.length(); j++) { + String decimal = x.substring(0, j); + String fraction = x.substring(j); + String newX = decimal + "." + fraction; + + boolean validNewX = valid(newX); + if (validNewX && validY) { + l.add("(" + newX + ", " + y + ")"); + } + + if (validNewX) { + for (int k = 1; k < y.length(); k++) { + decimal = y.substring(0, k); + fraction = y.substring(k); + String newY = decimal + "." + fraction; + if (valid(newY)) { + l.add("(" + newX + ", " + newY + ")"); + } + } + } + + } + + for (int j = 1; j < y.length(); j++) { + String decimal = y.substring(0, j); + String fraction = y.substring(j); + String newY = decimal + "." + fraction; + if (validX && valid(newY)) { + l.add("(" + x + ", " + newY + ")"); + } + } + } + + return l; + } + + private boolean valid(String s) { + if (s.length() == 0) return false; + if (s.length() == 1) return true; + + if (s.charAt(0) == '0' && s.charAt(1) != '.') return false; + + int nonZero = 0; + boolean hasPoint = false; + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (ch > '0' && ch <= '9') { + nonZero++; + } else if (ch == '.') { + nonZero = 0; + hasPoint = true; + } + } + + if (hasPoint && s.charAt(s.length() -1) == '0') return false; + return nonZero > 0; + } + + @Test + public void test() { + assertThat(ambiguousCoordinates("(123)"), hasItems("(1, 23)", "(12, 3)", "(1.2, 3)", "(1, 2.3)")); + assertThat(ambiguousCoordinates("(00011)"), hasItems("(0.001, 1)", "(0, 0.011)")); + assertThat(ambiguousCoordinates("(0123)"), hasItems("(0, 123)", "(0, 12.3)", "(0, 1.23)", "(0.1, 23)", "(0.1, 2.3)", "(0.12, 3)")); + assertThat(ambiguousCoordinates("(100)"), hasItems("(10, 0)")); + assertThat(ambiguousCoordinates("(0010)"), hasItems("(0.01, 0)")); + System.out.println(ambiguousCoordinates("(0101)")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ArrayRightRotation.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ArrayRightRotation.java new file mode 100644 index 0000000..ab1a703 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ArrayRightRotation.java @@ -0,0 +1,62 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; + +/** + * 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] + */ +public class ArrayRightRotation { + public void rotate(int[] nums, int k) { + // [5,6,7,1,2,3,4] + if (nums.length <= 1) return; + k = k % nums.length; + + int count = 0; + int i = 0; + while (count < nums.length) { + int start = i; + int temp = nums[i]; + + int end = (k + i) % nums.length; + while (start != end) { + int val = nums[end]; + nums[end] = temp; + temp = val; + end = (end + k) % nums.length; + count++; + } + nums[start] = temp; + count++; + i++; + } + + } + + @Test + public void test1() { + int[] expected = new int[] {5,6,7,1,2,3,4}; + int[] input = new int[] {1,2,3,4,5,6,7}; + rotate(input, 3); + assertArrayEquals(expected, input); + } + + + @Test + public void test2() { + int[] expected = new int[] {5,6,1,2,3,4}; + int[] input = new int[] {1,2,3,4,5,6}; + rotate(input, 2); + assertArrayEquals(expected, input); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculator.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculator.java new file mode 100644 index 0000000..466b7bc --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculator.java @@ -0,0 +1,75 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertEquals; + +/** + * Implement a basic calculator to evaluate a simple expression string. + * + * The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces . + * + * Example 1: + * + * Input: "1 + 1" + * Output: 2 + * Example 2: + * + * Input: " 2-1 + 2 " + * Output: 3 + * Example 3: + * + * Input: "(1+(4+5+2)-3)+(6+8)" + * Output: 23 + */ +public class BasicCalculator { + public int calculate(String s) { + s = s.replaceAll(" ", ""); + + Stack stack = new Stack<>(); + + int start = 0; + int mul = 1; + int end = 0; + for (end = 0; end < s.length(); end++) { + if (s.charAt(end) == '+' || s.charAt(end) == '-') { + if (start < end) { + int n = mul * Integer.valueOf(s.substring(start, end)); + stack.push(n); + } + + mul = s.charAt(end) == '-' ? -1: 1; + start = end + 1; + } else if (s.charAt(end) == '(') { + // find closing + int close = end + 1; + int openBrace = 0; + while (++end < s.length()) { + if (s.charAt(end) == '(') openBrace++; + if (s.charAt(end) == ')' && openBrace == 0) break; + else if (s.charAt(end) == ')') openBrace--; + } + stack.push(mul * calculate(s.substring(close, end))); + start = end + 1; + } + } + if (start < end) stack.push(mul * Integer.valueOf(s.substring(start))); + + int sum = 0; + while(!stack.isEmpty()) { + sum += stack.pop(); + } + return sum; + } + + @Test + public void test1() { + assertEquals(2, calculate("1 + 1")); + assertEquals(3, calculate("2 - 1 +2")); + assertEquals(-11, calculate("-12 - 1 +2")); + assertEquals(-9, calculate("-(12 - 1) +2")); + assertEquals(23, calculate("(1+(4+5+2)-3)+(6+8)")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculatorII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculatorII.java new file mode 100644 index 0000000..53dccb4 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculatorII.java @@ -0,0 +1,79 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * Implement a basic calculator to evaluate a simple expression string. + * + * The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer division should truncate toward zero. + * + * Example 1: + * + * Input: "3+2*2" + * Output: 7 + */ +public class BasicCalculatorII { + private List symbols = Arrays.asList('/', '*', '+', '-'); + + public int calculate(String str) { + str = str.replaceAll(" ", ""); + if (str.length() == 0) return 0; + if (str.length() == 1) return Integer.valueOf(str); + + int start = 0; + int end = 0; + + Stack s = new Stack<>(); + char lastOp = '#'; + while (end < str.length()) { + + while (end < str.length()) { + if (symbols.contains(str.charAt(end))) { + break; + } + end++; + } + // if the expression starts with '-', then it has to be taken care + if (end != 0) { + int n = Integer.valueOf(str.substring(start, end)); + if (lastOp == '*') { + int mul = s.isEmpty() ? 1 : s.pop(); + s.push(mul * n); + } else if (lastOp == '/') { + int mul = s.isEmpty() ? 0 : s.pop(); + s.push(mul / n); + } else if (lastOp == '-') { + s.push((-1) * n); + } else { + s.push(n); + } + } + if (end < str.length()) { + lastOp = str.charAt(end); + end = end + 1; + start = end; + } + + } + + int res = 0; + while (!s.isEmpty()) { + res += s.pop(); + } + return res; + } + + @Test + public void test() { + assertEquals(7, calculate("3+2*2")); + assertEquals(1, calculate("-3+2*2")); + assertEquals(1, calculate("1-1+1")); + assertEquals(27, calculate("3+2*2+4*5")); + assertEquals(5, calculate(" 3+5 / 2 ")); + assertEquals(-2147483647, calculate("0-2147483647")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculatorIII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculatorIII.java new file mode 100644 index 0000000..9f84f95 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BasicCalculatorIII.java @@ -0,0 +1,95 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/basic-calculator-iii/ + */ +public class BasicCalculatorIII { + public int calculate(String s) { + s = s.trim(); + + Stack stack = new Stack<>(); + + char sign = '#'; + + int curr = 0; + + for (int i = 0; i < s.length();) { + char ch = s.charAt(i); + + if (ch == ' ') { + i++; + continue; + } + + if ('0' <= ch && ch <= '9') { + curr = curr * 10 + (ch - '0'); + + if (i + 1 < s.length()) { + i++; + continue; + } + } else if (ch == '(') { + int j = i + 1; + + int open = 1; + while (j < s.length()) { + char close = s.charAt(j); + + if (close == '(') open++; + else if (close == ')') { + open--; + if (open == 0) { + break; + } + } + j++; + } + curr = calculate(s.substring(i + 1, j)); + i = j + 1; + + while (i < s.length()) { + ch = s.charAt(i); + if (ch == '-' || ch == '+' || ch == '*' || ch == '/') break; + i++; + } + } + + if (sign == '*') { + int prev = stack.pop(); + stack.push(prev * curr); + } else if (sign == '/') { + int prev = stack.pop(); + stack.push(prev / curr); + } else if (sign == '-') { + stack.push((-1) * curr); + } else { + stack.push(curr); + } + + sign = ch; + curr = 0; + i++; + } + + int res = 0; + + while (!stack.isEmpty()) { + res += stack.pop(); + } + return res; + } + + @Test + public void test() { + assertEquals(2, calculate("1 + 1")); + assertEquals(4, calculate(" 6-4 / 2 ")); + assertEquals(21, calculate("2*(5+5*2)/3+(6/2+8)")); + assertEquals(-12, calculate("(2+6* 3+5- (3*14/7+2)*5)+3")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BayerMooreTextSearch.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BayerMooreTextSearch.java new file mode 100644 index 0000000..b019a16 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BayerMooreTextSearch.java @@ -0,0 +1,74 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Given string text t of length m and pattern p of length n, find all the indices + * of the starting of p in t + * + * example: + * Text: abcabcdefabc + * P: abc + * + * output: [0,3,9] + */ +public class BayerMooreTextSearch { + public List searchPatterns(String t, String p) { + List l = new ArrayList<>(); + + if (t.length() < p.length()) return l; + + Set set = new HashSet<>(); + for (char ch: p.toCharArray()) { + set.add(ch); + } + + int end = p.length() - 1; + + while (end < t.length()) { + if (t.charAt(end) == p.charAt(p.length() - 1)) { + // do back search + boolean found = true; + int tIdx = 0; + for (int i = p.length() - 1; i >= 0; i--) { + if (t.charAt(end - tIdx++) != p.charAt(i)) { + found = false; + break; + } + } + if (found) { + l.add(end - p.length() + 1); + } + end++; + } else { + // if t.charAt(end) is one of char in p, then end++ + // else jump by p.length() + if (set.contains(t.charAt(end))) { + end++; + } else { + end += p.length(); + } + } + } + return l; + } + + @Test + public void test1() { + List expected = Arrays.asList(0, 3, 9); + List actual = searchPatterns("abcabcdefabc", "abc"); + assertThat(actual, is(expected)); + } + + @Test + public void test2() { + List expected = Arrays.asList(0, 2, 4, 6, 8); + List actual = searchPatterns("abababababa", "aba"); + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BinaryNumWAlternatingBits.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BinaryNumWAlternatingBits.java new file mode 100644 index 0000000..679655c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BinaryNumWAlternatingBits.java @@ -0,0 +1,37 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +/** + * https://leetcode.com/problems/binary-number-with-alternating-bits/ + * + */ +public class BinaryNumWAlternatingBits { + public boolean hasAlternatingBits(int n) { + boolean one = (n & 1) == 1; + while (n > 0) { + n = n >> 1; + int curr = n & 1; + if ((curr == 1 && one) || (curr == 0 && !one)) { + return false; + } + one = !one; + } + return true; + } + + @Test + public void test() { + assertTrue(hasAlternatingBits(1)); + assertTrue(hasAlternatingBits(2)); + assertFalse(hasAlternatingBits(4)); + assertTrue(hasAlternatingBits(5)); + assertFalse(hasAlternatingBits(7)); + assertFalse(hasAlternatingBits(8)); + assertTrue(hasAlternatingBits(10)); + assertFalse(hasAlternatingBits(11)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BinaryWatch.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BinaryWatch.java new file mode 100644 index 0000000..d925ef7 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BinaryWatch.java @@ -0,0 +1,57 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * A binary watch has 4 LEDs on the top which represent the hours (0-11), and the 6 LEDs on the bottom represent the minutes (0-59). + *

+ * Each LED represents a zero or one, with the least significant bit on the right. + *

+ *

+ * For example, the above binary watch reads "3:25". + *

+ * Given a non-negative integer n which represents the number of LEDs that are currently on, return all possible times the watch could represent. + *

+ * Example: + *

+ * Input: n = 1 + * Return: ["1:00", "2:00", "4:00", "8:00", "0:01", "0:02", "0:04", "0:08", "0:16", "0:32"] + *

+ * https://leetcode.com/problems/binary-watch/ + */ +public class BinaryWatch { + private int[] vals = new int[]{1, 2, 4, 8, 1, 2, 4, 8, 16, 32}; + + public List readBinaryWatch(int num) { + List res = new ArrayList<>(); + backTrack(num, res, 0, 0, 0); + return res; + } + + private void backTrack(int n, List res, int hour, int min, int start) { + if (n == 0) { + res.add(hour + ":" + (min < 10 ? "0" + min : min)); + } else { + for (int i = start; i < vals.length; i++) { + if (hour > 11 || min > 59) continue; + if (i <= 3) + backTrack(n - 1, res, hour + vals[i], min, i + 1); + else + backTrack(n - 1, res, hour, min + vals[i], i + 1); + } + } + } + + + @Test + public void test() { + List actual = readBinaryWatch(1); + List expected = Arrays.asList("1:00, 2:00, 4:00, 8:00, 0:01, 0:02, 0:04, 0:08, 0:16, 0:32".split(", ")); + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BraceExpansion.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BraceExpansion.java new file mode 100644 index 0000000..269a5d8 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BraceExpansion.java @@ -0,0 +1,65 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/brace-expansion/ + */ +public class BraceExpansion { + public String[] expand(String S) { + if (S.length() == 0) return new String[0]; + if (S.length() == 1) return new String[] {S}; + // if start {, then + List l = new ArrayList<>(); + + if (S.charAt(0) == '{') { + int i = 1; + while (S.charAt(i) != '}') { + i++; + } + String[] parts = S.substring(1, i).split(","); + Arrays.sort(parts); // to make words in lexicographical order + + String rem = S.substring(i + 1); + + String[] more = expand(rem); + + for (i = 0; i < parts.length; i++) { + if (more.length > 0) { + for (int j = 0; j < more.length; j++) { + l.add(parts[i] + more[j]); + } + } else { + l.add(parts[i]); + } + + } + } else { + String[] more = expand(S.substring(1)); + for (String str: more) { + l.add(S.charAt(0) + str); + } + + } + return l.toArray(new String[l.size()]); + } + + @Test + public void test1() { + String[] expected = {"acdf","acef","bcdf","bcef"}; + assertThat(expand("{a,b}c{d,e}f"), is(expected)); + } + + @Test + public void test2() { + String[] expected = {"abcd"}; + assertThat(expand("abcd"), is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BraceExpansionII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BraceExpansionII.java new file mode 100644 index 0000000..848535e --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BraceExpansionII.java @@ -0,0 +1,101 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/brace-expansion-ii/ + */ +public class BraceExpansionII { + public List braceExpansionII(String expression) { + if (expression.length() == 0) return Collections.emptyList(); + if (expression.length() == 1) return Collections.singletonList(expression); + + Set l = new HashSet<>(); + + if (expression.charAt(0) == '{') { + int i = 1; + int open = 1; + while (i < expression.length()) { + if (expression.charAt(i) == '{') { + open++; + } else if (expression.charAt(i) == '}') { + open--; + if (open == 0) break; + } + i++; + } + + String curr = expression.substring(1, i); + + List parts = new ArrayList<>(); + + int start = 0; + open = 0; + + int j = 0; + for (; j < curr.length(); j++) { + if (curr.charAt(j) == '{') { + open++; + } else if (curr.charAt(j) == '}') { + open--; + + } else if (curr.charAt(j) == ',' && open == 0) { + parts.addAll(braceExpansionII(curr.substring(start, j))); + start = j + 1; + open = 0; + } + } + parts.addAll(braceExpansionII(curr.substring(start, j))); + + List rem = braceExpansionII(expression.substring(i + 1)); + + for (String part: parts) { + if (rem.size() > 0) { + for (String sPart: rem) { + l.add(part + sPart); + } + } else { + l.add(part); + } + } + } else { + String prefix = ""; + + + int i = 0; + for (; i < expression.length(); i++) { + if (expression.charAt(i) == '{') { + break; + } else { + prefix += expression.charAt(i); + } + } + + List parts = braceExpansionII(expression.substring(i)); + + if (parts.size() > 0) { + for (String part: parts) { + l.add(prefix + part); + } + } else { + l.add(prefix); + } + + } + + List formed = new ArrayList<>(l); + formed.sort(Comparator.naturalOrder()); + return formed; + } + + @Test + public void test() { + List expected = Arrays.asList("a","ab","ac","z"); + assertThat(braceExpansionII("{{a,z},a{b,c},{ab,z}}"), is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BrickWall.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BrickWall.java new file mode 100644 index 0000000..7dd4c30 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BrickWall.java @@ -0,0 +1,55 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertEquals; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * https://leetcode.com/problems/brick-wall/ + */ +public class BrickWall { + public int leastBricks(List> wall) { + int m = wall.size(); + int n = 0; + for (int w: wall.get(0)) { + n += w; + } + + Map map = new HashMap<>(); + for (List row: wall) { + int brickSum = 0; + for (int w: row) { + brickSum += w; + map.put(brickSum, map.getOrDefault(brickSum, 0) + 1); + } + } + + int res = Integer.MAX_VALUE; + for (int w: map.keySet()) { + int count = map.get(w); + if (w < n) { + count = m - count; + } + res = Math.min (count, res); + } + + return res; + } + + @Test + public void test1() { + List> wall = asList(asList(1,2,2,1), + asList(3,1,2), + asList(1,3,2), + asList(2,4), + asList(3,1,2), + asList(1,3,1,1)); + int count = leastBricks(wall); + assertEquals(2, count); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BuySellStock.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BuySellStock.java new file mode 100644 index 0000000..bb59f38 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/BuySellStock.java @@ -0,0 +1,28 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ + */ +public class BuySellStock { + public int maxProfit(int[] prices) { + int minPrice = Integer.MAX_VALUE; + int profit = 0; + + for (int i = 0; i < prices.length; i++) { + if (minPrice > prices[i]) minPrice = prices[i]; + + if (prices[i] - minPrice > profit) profit = prices[i] - minPrice; + } + return profit; + } + + @Test + public void test() { + assertEquals(5, maxProfit(new int[]{7, 1, 5, 3, 6, 4})); + assertEquals(1, maxProfit(new int[]{1, 2})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CampusBike.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CampusBike.java new file mode 100644 index 0000000..a62a798 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CampusBike.java @@ -0,0 +1,66 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.PriorityQueue; + +import static org.junit.Assert.assertArrayEquals; + +/** + * https://leetcode.com/problems/campus-bikes/ + */ +public class CampusBike { + public int[] assignBikes(int[][] workers, int[][] bikes) { + int m = workers.length; + + int n = bikes.length; + + PriorityQueue pq = new PriorityQueue<>((p, q) -> { + int d = p[2] - q[2]; + if (d == 0) { + int w = p[0] - q[0]; + if (w == 0) return p[1] - q[1]; + return w; + } + return d; + }); + + for (int w = 0; w < m; w++) { + for (int b = 0; b < n; b++) { + int d = Math.abs(workers[w][0] - bikes[b][0]) + + Math.abs(workers[w][1] - bikes[b][1]); + pq.offer(new int[]{w, b, d}); + } + } + + int[] res = new int[m]; + + boolean[] used = new boolean[n]; + + Arrays.fill(res, -1); + + int count = 0; + while (!pq.isEmpty() && count < m) { + int[] curr = pq.poll(); + int w = curr[0]; + int b = curr[1]; + + if (res[w] == -1 && !used[b]) { + res[w] = b; + used[b] = true; + count++; + } + } + + return res; + } + + @Test + public void test() { + int[] expected = {0, 8, 2, 7, 1, 5, 3, 4}; + int[][] workers = {{664, 994}, {3, 425}, {599, 913}, {220, 352}, {145, 348}, {604, 428}, {519, 183}, {732, 148}}; + int[][] bikes = {{611, 698}, {113, 338}, {579, 770}, {276, 588}, {948, 679}, {731, 525}, {925, 877}, {182, 281}, {39, 299}}; + assertArrayEquals(expected, assignBikes(workers, bikes)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ClosestPoint2Origin.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ClosestPoint2Origin.java new file mode 100644 index 0000000..2ad0a01 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ClosestPoint2Origin.java @@ -0,0 +1,114 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.PriorityQueue; +import java.util.Random; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * We have a list of points on the plane. Find the K closest points to the origin (0, 0). + *

+ * (Here, the distance between two points on a plane is the Euclidean distance.) + *

+ * You may return the answer in any order. The answer is guaranteed to be unique (except for the order that it is in.) + *

+ *

+ *

+ * Example 1: + *

+ * Input: points = [[1,3],[-2,2]], K = 1 + * Output: [[-2,2]] + * Explanation: + * The distance between (1, 3) and the origin is sqrt(10). + * The distance between (-2, 2) and the origin is sqrt(8). + * Since sqrt(8) < sqrt(10), (-2, 2) is closer to the origin. + * We only want the closest K = 1 points from the origin, so the answer is just [[-2,2]]. + *

+ * https://leetcode.com/problems/k-closest-points-to-origin/ + */ +public class ClosestPoint2Origin { + private Random rnd = new Random(); + + /** + * With Sort - Time O(nlogn) + * With heap - Time O(nlogk) + * With Quick Sort - Time O(n) + * + * @param points + * @param k + * @return + */ + public int[][] kClosest(int[][] points, int k) { + int n = points.length; + + if (n == k) return points; + + int l = 0; + int r = n - 1; + + while (l <= r) { + int pivotIdx = l + rnd.nextInt(r - l + 1); + int pIdx = partition(points, l, r, pivotIdx); + + if (k == pIdx) return Arrays.copyOfRange(points, 0, k); + + if (pIdx > k) { + r = pIdx - 1; + } else { + l = pIdx + 1; + } + } + return null; + } + + private int partition(int[][] points, int l, int r, int p) { + int i = l; + + int pivot = dist(points[p]); + + swap(points, p, r); + + for (int j = l; j < r; j++) { + if (dist(points[j]) < pivot) { + swap(points, i, j); + i++; + } + } + + swap(points, i, r); + + return i; + } + + private int dist(int[] p) { + return p[0] * p[0] + p[1] * p[1]; + } + + private void swap(int[][] points, int i, int j) { + int[] temp = points[i]; + points[i] = points[j]; + points[j] = temp; + } + + @Test + public void test1() { + int[][] points = new int[][]{ + {1, 3}, + {-2, 2} + }; + int[][] kClosest = kClosest(points, 1); + int[][] expected = new int[][]{{-2, 2}}; + assertThat(kClosest, is(expected)); + } + + @Test + public void test2() { + int[][] points = {{0, 1}, {1, 0}}; + int[][] expected = {{0, 1}, {1, 0}}; + assertThat(kClosest(points, 2), is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CoinChangeII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CoinChangeII.java new file mode 100644 index 0000000..03ff441 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CoinChangeII.java @@ -0,0 +1,87 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * You are given coins of different denominations and a total amount of money. + * Write a function to compute the number of combinations that make up that amount. You may assume that you have infinite number of each kind of coin. + * + * + * + * Example 1: + * + * Input: amount = 5, coins = [1, 2, 5] + * Output: 4 + * Explanation: there are four ways to make up the amount: + * 5=5 + * 5=2+2+1 + * 5=2+1+1+1 + * 5=1+1+1+1+1 + * + * + * https://leetcode.com/problems/coin-change-2/ + */ +public class CoinChangeII { + + public int change(int amount, int[] coins) { + // memoization with amount and coin index + // so that no need to recalculate for that amount and given coins + int[][] mem = new int[amount + 1][coins.length]; + for (int r = 0; r <= amount; r++) { + for (int c = 0; c < coins.length; c++) { + mem[r][c] = -1; + } + } + return change(amount, coins, 0, mem); + } + + private int change(int amt, int[] coins, int start, int[][] mem) { + if (amt == 0) { + return 1; + } + + if (amt < 0 || start == coins.length) return 0; + if (mem[amt][start] != -1) return mem[amt][start]; + int cnt = 0; + + for (int i = start; i < coins.length; i++) { + cnt += change(amt - coins[i], coins, i, mem); + } + mem[amt][start] = cnt; + return mem[amt][start]; + } + + @Test + public void test1() { + assertEquals(4, change(5, new int[]{1, 2, 5})); + assertEquals(0, change(3, new int[]{2})); + assertEquals(1, change(10, new int[]{10})); + assertEquals(35502874, change(500, new int[]{3, 5, 7, 8, 9, 10, 11})); + assertEquals(0, change(500, new int[]{})); + assertEquals(1, change(0, new int[]{})); + } + + public int changeDp(int amount, int[] coins) { + int[] dp = new int[amount + 1]; + dp[0] = 1; + + for (int i = 0; i < coins.length; i++) { + for (int j = coins[i]; j < dp.length; j++) { + dp[j] += dp[j - coins[i]]; + } + } + return dp[amount]; + } + + @Test + public void testDp() { + assertEquals(4, changeDp(5, new int[]{1, 2, 5})); + assertEquals(0, changeDp(3, new int[]{2})); + assertEquals(1, changeDp(10, new int[]{10})); + assertEquals(35502874, changeDp(500, new int[]{3, 5, 7, 8, 9, 10, 11})); + assertEquals(0, changeDp(500, new int[]{})); + assertEquals(1, changeDp(0, new int[]{})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CombinationSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CombinationSum.java new file mode 100644 index 0000000..4e49132 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CombinationSum.java @@ -0,0 +1,88 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Given a set of candidate numbers (candidates) (without duplicates) and a target number (target), + * find all unique combinations in candidates where the candidate numbers sums to target. + *

+ * The same repeated number may be chosen from candidates unlimited number of times. + *

+ * Note: + *

+ * All numbers (including target) will be positive integers. + * The solution set must not contain duplicate combinations. + * Example 1: + *

+ * Input: candidates = [2,3,6,7], target = 7, + * A solution set is: + * [ + * [7], + * [2,2,3] + * ] + */ +public class CombinationSum { + + /** + * Time - O(n!) + * Space - O(n) + * + * @param candidates + * @param target + * @return + */ + public List> combinationSum(int[] candidates, int target) { + List> l = new ArrayList<>(); + if (candidates.length == 0) return l; + + // this is important as we are pruning the search with index + Arrays.sort(candidates); + backTrack(candidates, 0, new ArrayList<>(), l, target); + + return l; + } + + private void backTrack(int[] candidates, int start, List temp, List> r, int target) { + if (target == 0) { // found the set of element + r.add(new ArrayList<>(temp)); + } else { + for (int i = start; i < candidates.length; i++) { + int n = candidates[i]; + + if (target - n < 0) return; + + temp.add(n); + backTrack(candidates, i, temp, r, target - n); + temp.remove(temp.size() - 1); + } + } + } + + @Test + public void test1() { + List> actual = combinationSum(new int[]{2, 3, 6, 7}, 7); + + List> expected = new ArrayList<>(); + expected.add(Arrays.asList(2, 2, 3)); + expected.add(Arrays.asList(7)); + assertThat(actual, is(expected)); + } + + @Test + public void test2() { + List> actual = combinationSum(new int[]{2, 3, 5}, 8); + List> expected = new ArrayList<>(); + expected.add(Arrays.asList(2, 2, 2, 2)); + expected.add(Arrays.asList(2, 3, 3)); + expected.add(Arrays.asList(3, 5)); + + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Combinations.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Combinations.java new file mode 100644 index 0000000..14c4d42 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Combinations.java @@ -0,0 +1,63 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Given two integers n and k, return all possible combinations of k numbers out of 1 ... n. + * + * Example: + * + * Input: n = 4, k = 2 + * Output: + * [ + * [2,4], + * [3,4], + * [2,3], + * [1,2], + * [1,3], + * [1,4], + * ] + */ +public class Combinations { + public List> combine(int n, int k) { + List> l = new ArrayList<>(); + + if (n == 0) return l; + + backTrack(n, 1, k, l, new ArrayList<>()); + return l; + } + + private void backTrack(int n, int start, int k, List> l, List temp) { + if (temp.size() == k) { + l.add(new ArrayList<>(temp)); + } else { + for (int i = start; i <= n; i++) { + temp.add(i); + backTrack(n, i + 1, k, l, temp); + temp.remove(temp.size() - 1); + } + } + } + + @Test + public void test1() { + List> actual = combine(4, 2); + List> expected = new ArrayList<>(); + expected.add(Arrays.asList(1,2)); + expected.add(Arrays.asList(1,3)); + expected.add(Arrays.asList(1,4)); + expected.add(Arrays.asList(2,3)); + expected.add(Arrays.asList(2,4)); + expected.add(Arrays.asList(3,4)); + + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CompareStrings.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CompareStrings.java new file mode 100644 index 0000000..a75165c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CompareStrings.java @@ -0,0 +1,75 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertArrayEquals; + +/** + * One string A strictly smaller than other B if the count(firstSamllestChar A) < count(firstSmallestChar B) + * + * for given array of strings with B, return C[j] where C[j] represents count of smaller strings than C[j] in A + */ +public class CompareStrings { + // Time O(m * n) where m -> length of B, n -> length of A + public int[] compareStrings(String A, String B) { + String[] a = A.split(" "); + String[] b = B.split(" "); + + Map map = new HashMap<>(); + + for (String aa: a) { + map.put(aa, count(aa)); + } + + int len = b.length; + + int[] res = new int[len]; + + for (int i = 0; i < len; i++) { // O(m * n) + res[i] = countStrings(a, map, b[i]); + } + + return res; + } + + private int countStrings(String[] arr, Map map, String str) { + int count = 0; + + int[] bCount = count(str); + + for (String a: arr) { + int[] aCount = map.get(a); + + // if b is strictly larger, then count + 1 + int aVal = 0; + int bVal = 0; + for (int i = 0; i < 26; i++) { + if (aCount[i] > 0 && aVal == 0) aVal = aCount[i]; + + if (bCount[i] > 0 && bVal == 0) bVal = bCount[i]; + } + + if (bVal > aVal) count++; + } + + return count; + } + + private int[] count(String str) { + int[] arr = new int[26]; + + for (char ch: str.toCharArray()) { + arr[ch - 'a']++; + } + + return arr; + } + + @Test + public void test() { + assertArrayEquals(new int[] { 3, 2}, compareStrings("abcd aabc bd", "aaa aa")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ComplexNumberMul.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ComplexNumberMul.java new file mode 100644 index 0000000..d082b61 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ComplexNumberMul.java @@ -0,0 +1,40 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Given two strings representing two complex numbers. + * + * You need to return a string representing their multiplication. Note i2 = -1 according to the definition. + * + * Example 1: + * Input: "1+1i", "1+1i" + * Output: "0+2i" + * Explanation: (1 + i) * (1 + i) = 1 + i2 + 2 * i = 2i, and you need convert it to the form of 0+2i. + * + * + * https://leetcode.com/problems/complex-number-multiplication/ + */ +public class ComplexNumberMul { + public String complexNumberMultiply(String a, String b) { + String[] arr = a.split("\\+"); + int x1 = Integer.valueOf(arr[0]); + int y1 = Integer.valueOf(arr[1].substring(0, arr[1].length() - 1)); + + String[] brr = b.split("\\+"); + int x2 = Integer.valueOf(brr[0]); + int y2 = Integer.valueOf(brr[1].substring(0, brr[1].length() - 1)); + + int x = x1 * x2 - y1 * y2; + int y = x1 * y2 + x2 * y1; + + return x + "+" + y + "i"; + } + + @Test + public void test() { + assertEquals("0+2i", complexNumberMultiply("1+1i", "1+1i")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Count1sSquareSubmatrices.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Count1sSquareSubmatrices.java new file mode 100644 index 0000000..4baa857 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Count1sSquareSubmatrices.java @@ -0,0 +1,42 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/count-square-submatrices-with-all-ones/ + */ +public class Count1sSquareSubmatrices { + public int countSquares(int[][] matrix) { + int m = matrix.length; + if (m == 0) return 0; + int n = matrix[0].length; + int count = 0; + + int[][] mem = new int[m + 1][n + 1]; + + for (int row = 1; row <= m; row++) { + for (int col = 1; col <= n; col++) { + if (matrix[row - 1][col - 1] == 1) { + mem[row][col] = 1 + Math.min(mem[row - 1][col - 1], + Math.min(mem[row - 1][col], mem[row][col - 1])); + count += mem[row][col]; + } + } + } + + return count; + } + + @Test + public void test() { + int[][] matrix = new int[][]{ + {0, 1, 1, 1}, + {1, 1, 1, 1}, + {0, 1, 1, 1} + }; + + assertEquals(15, countSquares(matrix)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CountOfRangeSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CountOfRangeSum.java new file mode 100644 index 0000000..8098417 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CountOfRangeSum.java @@ -0,0 +1,68 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/count-of-range-sum/ + */ +public class CountOfRangeSum { + public int countRangeSum(int[] nums, int lower, int upper) { + + long[] sum = new long[nums.length + 1]; + for (int i = 1; i <= nums.length; i++) { + sum[i] = sum[i - 1] + nums[i - 1]; + } + + return mergeSort(sum, 0, sum.length - 1, lower, upper); + } + + private int mergeSort(long[] arr, int lo, int hi, int lower, int upper) { + if (lo >= hi) return 0; + int mid = lo + (hi - lo) / 2; + + int count = mergeSort(arr, lo, mid, lower, upper) + mergeSort(arr, mid + 1, hi, lower, upper); + + for (int i = lo, j = mid + 1, k = mid + 1; i <= mid; i++) { + while (j <= hi && arr[j] - arr[i] < lower) j++; + while (k <= hi && arr[k] - arr[i] <= upper) k++; + + count += (k - j); + } + + merge(arr, lo, mid, hi); + + return count; + } + + private void merge(long[] arr, int lo, int mid, int hi) { + long[] copy = new long[hi - lo + 1]; + + int p = lo; + int q = mid + 1; + int i = 0; + while (p <= mid && q <= hi) { + if (arr[p] < arr[q]) { + copy[i++] = arr[p++]; + } else { + copy[i++] = arr[q++]; + } + } + + while (p <= mid) { + copy[i++] = arr[p++]; + } + + while (q <= hi) { + copy[i++] = arr[q++]; + } + + System.arraycopy(copy, 0, arr, lo, hi - lo + 1); + } + + @Test + public void test() { + assertEquals(3, countRangeSum(new int[]{-2, 5, -1}, -2, 2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CustomSortString.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CustomSortString.java new file mode 100644 index 0000000..69c69b7 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/CustomSortString.java @@ -0,0 +1,47 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/custom-sort-string/ + */ +public class CustomSortString { + public String customSortString(String S, String T) { + // count[char] = the number of occurrences of 'char' in T. + // This is offset so that count[0] = occurrences of 'a', etc. + // 'count' represents the current state of characters + // (with multiplicity) we need to write to our answer. + int[] count = new int[26]; + for (char c: T.toCharArray()) + count[c - 'a']++; + + // ans will be our final answer. We use StringBuilder to join + // the answer so that we more efficiently calculate a + // concatenation of strings. + StringBuilder ans = new StringBuilder(); + + // Write all characters that occur in S, in the order of S. + for (char c: S.toCharArray()) { + for (int i = 0; i < count[c - 'a']; ++i) + ans.append(c); + // Setting count[char] to zero to denote that we do + // not need to write 'char' into our answer anymore. + count[c - 'a'] = 0; + } + + // Write all remaining characters that don't occur in S. + // That information is specified by 'count'. + for (char c = 'a'; c <= 'z'; ++c) + for (int i = 0; i < count[c - 'a']; ++i) + ans.append(c); + + return ans.toString(); + } + + @Test + public void test() { + assertEquals("cbad", customSortString("cba", "abcd")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DecodeString.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DecodeString.java new file mode 100644 index 0000000..db07b67 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DecodeString.java @@ -0,0 +1,74 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/decode-string/ + */ +public class DecodeString { + /** + * Do recursive call if there is nested string to form input format + * + * @param s + * @return + */ + public String decodeString(String s) { + Stack stack = new Stack<>(); // + StringBuilder num = new StringBuilder(); + StringBuilder str = new StringBuilder(); + StringBuilder res = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) >= '0' && s.charAt(i) <= '9') { + num.append(s.charAt(i)); // nums = '2' + if (str.length() > 0) { + res.append(str.toString()); + str = new StringBuilder(); + } + } else if (s.charAt(i) == '[') { + stack.push(num.toString()); // stack = ['3'] + // find close and call + int start = ++i; // 1 + int open = 0; + for (; i < s.length(); i++) { + if (s.charAt(i) == '[') { + open++; + } else if (s.charAt(i) == ']') { + if (open == 0) { + + break; + } + open--; + } + } + str.append(decodeString(s.substring(start, i))); + num = new StringBuilder(); // nums = '' + i--; + } else if (s.charAt(i) == ']') { + String curr = stack.pop(); + try { + Integer times = Integer.valueOf(curr); + for (int j = 0 ; j < times; j++) { + res.append(str.toString()); + } + + } catch (NumberFormatException nfe) { + + } + str = new StringBuilder(); + } else { + str.append(s.charAt(i)); + } + } + res.append(str.toString()); + return res.toString(); + } + + @Test + public void test1() { + assertEquals("accaccacc", decodeString("3[a2[c]]")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DecreasingSubsequence.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DecreasingSubsequence.java new file mode 100644 index 0000000..a5817ff --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DecreasingSubsequence.java @@ -0,0 +1,69 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Given an int array nums of length n. Split it into strictly decreasing subsequences. Output the min number of subsequences you can get by splitting. + * + * Example 1: + * + * Input: [5, 2, 4, 3, 1, 6] + * Output: 3 + * Explanation: + * You can split this array into: [5, 2, 1], [4, 3], [6]. And there are 3 subsequences you get. + * Or you can split it into [5, 4, 3], [2, 1], [6]. Also 3 subsequences. + * But [5, 4, 3, 2, 1], [6] is not legal because [5, 4, 3, 2, 1] is not a subsuquence of the original array. + * Example 2: + * + * Input: [2, 9, 12, 13, 4, 7, 6, 5, 10] + * Output: 4 + * Explanation: [2], [9, 4], [12, 10], [13, 7, 6, 5] + * Example 3: + * + * Input: [1, 1, 1] + * Output: 3 + * Explanation: Because of the strictly descending order you have to split it into 3 subsequences: [1], [1], [1] + */ +public class DecreasingSubsequence { + public int decreasingSubseqences(int[] arr) { + int len = 0; + int n = arr.length; + + if (n == 0) return 0; + + int[] seq = new int[n]; + + for (int a: arr) { + int idx = search(seq, 0, len, a); + + seq[idx] = a; + + if (idx == len) len++; + } + + return len; + } + + private int search(int[] arr, int lo, int hi, int target) { + while (lo < hi) { + int mid = (lo + hi) / 2; + + if (arr[mid] <= target) { + lo = mid + 1; + } else { + hi = mid; + } + } + + return lo; + } + + @Test + public void test() { + assertEquals(3, decreasingSubseqences(new int[] {5, 2, 4, 3, 1, 6})); + assertEquals(4, decreasingSubseqences(new int[] {2, 9, 12, 13, 4, 7, 6, 5, 10})); + assertEquals(3, decreasingSubseqences(new int[] {1, 1, 1})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DiceRollWithTarget.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DiceRollWithTarget.java new file mode 100644 index 0000000..9b7b9a4 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DiceRollWithTarget.java @@ -0,0 +1,37 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/number-of-dice-rolls-with-target-sum/ + */ +public class DiceRollWithTarget { + public int numRollsToTarget(int d, int f, int target) { + int mod = 1000000007; + int[] ways = new int[target + 1]; + ways[0] = 1; + for (int i = 1; i <= d; i++) { + int[] newWays = new int[target + 1]; + + for (int j = 0; j <= target; j++) { + for (int k = 1; k <= f; k++) { + if (j >= k) { + newWays[j] += ways[j - k]; + newWays[j] %= mod; + } + + } + } + ways = newWays; + } + + return ways[target]; + } + + @Test + public void test() { + assertEquals(1, numRollsToTarget(1, 6, 3)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DivideArrayKSubArr.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DivideArrayKSubArr.java new file mode 100644 index 0000000..8a81290 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DivideArrayKSubArr.java @@ -0,0 +1,48 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; +import org.springframework.stereotype.Repository; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + + +/** + * https://leetcode.com/problems/divide-array-in-sets-of-k-consecutive-numbers/ + */ +public class DivideArrayKSubArr { + public boolean isPossibleDivide(int[] nums, int k) { + + int n = nums.length; + if (n % k != 0) return false; + + int r = n / k; + int[][] partitions = new int[r][k]; + + int[] pos = new int[r]; + + for (int num: nums) { + // n has to go any of parititions + for (int i = 0; i < partitions.length; i++) { + if (pos[i] >= k) continue; + + if (pos[i] == 0 || num == partitions[i][pos[i] - 1] + 1) { + partitions[i][pos[i]] = num; + pos[i]++; + break; + } + } + } + + for (int p: pos) { + if (p != k) return false; + } + return true; + } + + @Test + public void test() { + assertFalse(isPossibleDivide(new int[] {15,16,17,18,19,16,17,18,19,20,6,7,8,9,10,3,4,5,6,20}, 5)); + assertTrue(isPossibleDivide(new int[] {1,2,3,3,4,4,5,6}, 4)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DoublePairArray.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DoublePairArray.java new file mode 100644 index 0000000..ae2be8b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/DoublePairArray.java @@ -0,0 +1,55 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static junit.framework.TestCase.assertTrue; + + +/** + * Given an array of integers A with even length, return true if and only if it is possible to reorder + * it such that A[2 * i + 1] = 2 * A[2 * i] for every 0 <= i < len(A) / 2. + * + * https://leetcode.com/problems/array-of-doubled-pairs/ + */ +public class DoublePairArray { + public boolean canReorderDoubled(int[] A) { + Arrays.sort(A); + Map m = new HashMap<>(); + + for (int n: A) { + m.put(n, m.getOrDefault(n, 0) + 1); + } + + for (int n: A) { + if (!m.containsKey(n)) continue; // n has already been processed + int pair = 2 * n; // n = 0, pair = 0, map [(0,1)] + if (m.containsKey(pair)) { + + int updated = m.get(n) - 1; // 0 + if (updated == 0) m.remove(n); + else { + m.put(n, updated); + } + + if (pair != n) { + int updatedPair = m.get(pair) - 1; // -1 + if (updatedPair == 0) m.remove(pair); + else { + m.put(pair, updatedPair); + } + } + } + } + return m.size() == 0; + } + + @Test + public void test() { + assertTrue(canReorderDoubled(new int[] {0, 0})); + assertTrue(canReorderDoubled(new int[] {1,2,1,-8,8,-4,4,-4,2,-2})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/EditDistance.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/EditDistance.java new file mode 100644 index 0000000..444917a --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/EditDistance.java @@ -0,0 +1,79 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/edit-distance/ + * + * Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2. + * + * You have the following 3 operations permitted on a word: + * + * Insert a character + * Delete a character + * Replace a character + * Example 1: + * + * Input: word1 = "horse", word2 = "ros" + * Output: 3 + * Explanation: + * horse -> rorse (replace 'h' with 'r') + * rorse -> rose (remove 'r') + * rose -> ros (remove 'e') + */ +public class EditDistance { + public int minDistance(String word1, String word2) { + + + int m = word1.length(); + int n = word2.length(); + + int[][] mem = new int[m + 1][n + 1]; + + for (int i = 0; i <= m; i++) { + for (int j = 0; j <= n; j++) { + if (i == 0) { + mem[i][j] = j; + } else if (j == 0) { + mem[i][j] = i; + } else if (word1.charAt(i - 1) == word2.charAt(j - 1)) { + mem[i][j] = mem[i - 1][j - 1]; + } else { + mem[i][j] = 1 + Math.min(mem[i - 1][j - 1], Math.min( + mem[i - 1][j], mem[i][j - 1])); + } + } + } + return mem[m][n]; + + + /* + + // recursive + // if charAt(0) are same for both, then keep going + // else, min(change, delete on s1, delete on s2) + + if (word1.length() == 0 && word2.length() == 0) return 0; + if (word1.length() == 0) return word2.length(); + if (word2.length() == 0) return word1.length(); + + int count = 0; + if (word1.charAt(0) == word2.charAt(0)) { + count += minDistance(word1.substring(1), word2.substring(1)); + } else { + count += 1 + Math.min(minDistance(word1.substring(1), word2.substring(1)), Math.min(minDistance(word1.substring(1), word2), + minDistance(word1, word2.substring(1)))); + } + return count; + */ + } + + @Test + public void test() { + assertEquals(3, minDistance("horse", "ros")); + assertEquals(5, minDistance("intention", "execution")); + assertEquals(6, minDistance("dinitrophenylhydrazine","acetylphenylhydrazine")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/EvaluateDivision.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/EvaluateDivision.java new file mode 100644 index 0000000..640ed30 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/EvaluateDivision.java @@ -0,0 +1,120 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertArrayEquals; + +/** + * https://leetcode.com/problems/evaluate-division/submissions/ + * + * Equations are given in the format A / B = k, where A and B are variables represented as strings, and k is a real number (floating point number). + * Given some queries, return the answers. If the answer does not exist, return -1.0. + * + * Example: + * Given a / b = 2.0, b / c = 3.0. + * queries are: a / c = ?, b / a = ?, a / e = ?, a / a = ?, x / x = ? . + * return [6.0, 0.5, -1.0, 1.0, -1.0 ]. + * + * The input is: vector> equations, vector& values, vector> queries , + * where equations.size() == values.size(), and the values are positive. This represents the equations. Return vector. + * + * According to the example above: + * + * equations = [ ["a", "b"], ["b", "c"] ], + * values = [2.0, 3.0], + * queries = [ ["a", "c"], ["b", "a"], ["a", "e"], ["a", "a"], ["x", "x"] ]. + */ +public class EvaluateDivision { + public double[] calcEquation(List> equations, double[] values, List> queries) { + int n = values.length; + + // construct graph with adj list + Map> graph = new HashMap<>(); + + for (int i = 0; i < n; i++) { + List eq = equations.get(i); + String u = eq.get(0); + String v = eq.get(1); + + double w = values[i]; + + // this is for edge u -> v + if (!graph.containsKey(u)) { + graph.put(u, new ArrayList<>()); + } + List uNeighbors = graph.get(u); + uNeighbors.add(new Pair(v, w)); + + // there is also an edge v -> u with weight 1/w + if (!graph.containsKey(v)) { + graph.put(v, new ArrayList<>()); + } + List vNeighbors = graph.get(v); + vNeighbors.add(new Pair(u, (1.0) / w)); + } + + double[] res = new double[queries.size()]; + + for (int i = 0; i < queries.size(); i++) { + List q = queries.get(i); + String u = q.get(0); + String v = q.get(1); + + // if there is no node with either of u or v, then division not possible + if (!graph.containsKey(u) || !graph.containsKey(v)) { + res[i] = -1.0; + } else { // else do bfs + res[i] = bfs(graph, u, v); + } + } + + return res; + } + + private double bfs(Map> graph, String src, String dst) { + + Pair srcPair = new Pair(src, 1.0); + Queue q = new LinkedList<>(); + q.add(srcPair); + + Set visited = new HashSet<>(); + + while (!q.isEmpty()) { + Pair p = q.poll(); + visited.add(p.name); + + if (p.name.equals(dst)) { + return p.val; + } + + for (Pair n : graph.get(p.name)) { + if (!visited.contains(n.name)) { + double newVal = n.val * p.val; + q.add(new Pair(n.name, newVal)); + } + } + } + return -1.0; + } + + class Pair { + String name; + double val; + + Pair(String name, double val) { + this.name = name; + this.val = val; + } + } + + @Test + public void test() { + assertArrayEquals( + new double[] {6.00000,0.50000,-1.00000,1.00000,-1.00000}, + calcEquation(asList(asList("a","b"),asList("b","c")), new double[] { 2.0,3.0}, asList(asList("a","c"),asList("b","a"),asList("a","e"),asList("a","a"),asList("x","x"))), + 0.0); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ExpressionsAddOperators.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ExpressionsAddOperators.java new file mode 100644 index 0000000..f914c0e --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ExpressionsAddOperators.java @@ -0,0 +1,99 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/expression-add-operators/ + * + * + * Given a string that contains only digits 0-9 and a target value, return all possibilities to + * add binary operators (not unary) +, -, or * between the digits so they evaluate to the target value. + * + * Example 1: + * + * Input: num = "123", target = 6 + * Output: ["1+2+3", "1*2*3"] + */ +public class ExpressionsAddOperators { + public List addOperators(String num, int target) { + List l = new ArrayList<>(); + if (num.length() == 0) return l; + + bt(num, target, l, 1, "" + num.charAt(0)); + return l; + } + + private void bt(String num, int target, List l, int i, String exp) { + if (i == num.length()) { + if (evaluate(exp) == target) { + l.add(exp); + } + return; + } + + bt(num, target, l, i + 1, exp + num.charAt(i)); // no op + bt(num, target, l, i + 1, exp + "+" + num.charAt(i)); + bt(num, target, l, i + 1, exp + "-" + num.charAt(i)); + bt(num, target, l, i + 1, exp + "*" + num.charAt(i)); + } + + private long evaluate(String exp) { + + Stack stack = new Stack<>(); + + char lastExp = '#'; + + long curr = 0; + for (int i = 0; i < exp.length(); i++) { + if ('0' <= exp.charAt(i) && exp.charAt(i) <= '9') { + if (curr == 0 && exp.charAt(i) == '0' + && (i + 1) < exp.length() + && '0' <= exp.charAt(i + 1) && exp.charAt(i + 1) <= '9') + return Integer.MAX_VALUE; + + curr = curr * 10 + (exp.charAt(i) - '0'); + continue; + } + + if (lastExp == '*') { + stack.push(stack.pop() * curr); + } else if (lastExp == '-') { + stack.push(-curr); + } else { + stack.push(curr); + } + lastExp = exp.charAt(i); + curr = 0; + } + + if (lastExp == '*') { + stack.push(stack.pop() * curr); + } else if (lastExp == '-') { + stack.push(-curr); + } else { + stack.push(curr); + } + + + long val = 0; + + while (!stack.isEmpty()) { + val += stack.pop(); + } + return val; + } + + @Test + public void test() { + assertThat(addOperators("123", 6), is(Arrays.asList("1+2+3", "1*2*3"))); + assertThat(addOperators("105", 5), is(Arrays.asList("10-5", "1*0+5"))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ExpressiveWords.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ExpressiveWords.java new file mode 100644 index 0000000..6605604 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ExpressiveWords.java @@ -0,0 +1,55 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/expressive-words/ + */ +public class ExpressiveWords { + public int expressiveWords(String S, String[] words) { + int count = 0; + for (String word : words) { + if (sketchy(word, S)) count++; + } + return count; + } + + private boolean sketchy(String word, String sketch) { + + int i = 0, j = 0; + while (i < word.length() && j < sketch.length()) { + char p = word.charAt(i); + char q = sketch.charAt(j); + + if (p != q) return false; + + int pc = 0; + int qc = 0; + while (i < word.length() && p == word.charAt(i)) { + pc++; + i++; + } + + while (j < sketch.length() && q == sketch.charAt(j)) { + qc++; + j++; + } + + if (pc > qc) return false; + + int diff = qc - pc; + + if (diff != 0 && diff + pc < 3) return false; + } + + return i == word.length() && j == sketch.length(); + } + + @Test + public void test() { + assertEquals(3, expressiveWords("dddiiiinnssssssoooo", new String[] {"dinnssoo","ddinso","ddiinnso","ddiinnssoo","ddiinso","dinsoo","ddiinsso","dinssoo","dinso"})); + assertEquals(1, expressiveWords("heeellooo", new String[]{"hello", "hi", "helo"})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FillMatrix.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FillMatrix.java new file mode 100644 index 0000000..96af543 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FillMatrix.java @@ -0,0 +1,129 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; + +/** + * Given a NxN matrix. Fill the integers from 1 to n*n to this matrix that makes the sum of each row, each column and the two diagonals equal. + *

+ * Example 1: + *

+ * Input: n = 2 + * Output: null + * Explanation: We need to fill [1, 2, 3, 4] into a 2x2 matrix, which is not possible so return null. + * Example 2: + *

+ * Input: n = 3 + * Output: + * [[8, 3, 4], + * [1, 5, 9], + * [6, 7, 2]] + * Explanation: We need to fill [1, 2, 3... 9] into a 3x3 matrix. This is one way to do it + * Each row [8, 3, 4] [1, 5, 9] [6, 7, 2] sum is 15. + * Each column [8, 1, 6] [3, 5, 7] [4, 9, 2] sum is 15. + * The two diagonals [8, 5, 2] [4, 5, 6] sum is 15. + */ +public class FillMatrix { + // sum = 9 * 8 / 2 = 9* 4 = 45 + // rowSum = sum / 3 = 15 + public int[][] fillMatrix(int n) { + // if there is no way we can get a row with rowSum, then return null + int target = n * (n * n + 1) / 2; + + int[][] mat = new int[n][n]; + + for (int i = 0; i < n; i++) { + Arrays.fill(mat[i], -1); + } + + boolean[] visited = new boolean[n * n + 1]; + + if (fill(mat, 0, 0, target, visited)) return mat; + return null; + } + + private boolean fill(int[][] matrix, int r, int c, int target, boolean[] visited) { + + + int n = matrix.length; + if (c == n) { + c = 0; + r++; + } + + if (r == n) { + return valid(matrix, target); + } + + for (int i = 1; i <= n * n; i++) { + if (!visited[i]) { + visited[i] = true; + matrix[r][c] = i; + + if (fill(matrix, r, c + 1, target, visited)) { + return true; + } + + matrix[r][c] = -1; + visited[i] = false; + } + } + + return false; + } + + private boolean valid(int[][] matrix, int target) { + // row sums + int n = matrix.length; + for (int i = 0; i < n; i++) { + int sum = 0; + for (int j = 0; j < n; j++) { + sum += matrix[i][j]; + } + + if (sum != target) return false; + } + + // col sum + for (int j = 0; j < n; j++) { + int sum = 0; + for (int i = 0; i < n; i++) { + sum += matrix[i][j]; + } + + if (sum != target) return false; + } + + // main diagonal + int sum = 0; + for (int i = 0, j = 0; i < n && j < n; j++, i++) { + sum += matrix[i][j]; + } + + if (sum != target) return false; + + sum = 0; + + // anti diagonal + for (int i = 0, j = n - 1; i < n; i++, j--) { + sum += matrix[i][j]; + } + + if (sum != target) return false; + + return true; + } + + @Test + public void test() { + int[][] expected = {{2, 7, 6}, {9, 5, 1}, {4, 3, 8}}; + assertThat(fillMatrix(3), is(expected)); + + assertNull(fillMatrix(2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FindAllAnagrams.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FindAllAnagrams.java new file mode 100644 index 0000000..171e23d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FindAllAnagrams.java @@ -0,0 +1,81 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.CoreMatchers.is; + +/** + * Given a string s and a non-empty string p, find all the start indices of p's anagrams in s. + * + * Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100. + * + * The order of output does not matter. + * + * Example 1: + * + * Input: + * s: "cbaebabacd" p: "abc" + * + * Output: + * [0, 6] + * + * Explanation: + * The substring with start index = 0 is "cba", which is an anagram of "abc". + * The substring with start index = 6 is "bac", which is an anagram of "abc". + */ +public class FindAllAnagrams { + public List findAnagrams(String s, String p) { + List l = new ArrayList<>(); + if (s.length() < p.length()) return l; + Map map = new HashMap<>(); + for (char ch: p.toCharArray()) { + map.put(ch, map.getOrDefault(ch, 0) + 1); + } + + int end = p.length() - 1; + + while (end < s.length()) { + if (map.containsKey(s.charAt(end))) { + // match + Map temp = new HashMap<>(map); + + int j = 0; + for (int i = p.length() - 1; i >= 0; i--) { + char ch = s.charAt(end - j++); + if (!temp.containsKey(ch)) { + break; + } + + int count = temp.get(ch) - 1; + if (count == 0) temp.remove(ch); + else temp.put(ch, count); + } + + if (temp.isEmpty()) { + l.add(end - p.length() + 1); + } + end++; + } else { + end += p.length(); + } + } + return l; + } + + @Test + public void test1() { + List expected = Arrays.asList(0, 6); + List actual = findAnagrams("cbaebabacd", "abc"); + assertThat(actual, is(expected)); + } + + @Test + public void test2() { + List expected = Arrays.asList(0, 1, 2); + List actual = findAnagrams("abab", "ab"); + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FloweringWater.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FloweringWater.java new file mode 100644 index 0000000..088c968 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FloweringWater.java @@ -0,0 +1,49 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Count how many times you and your friend, who is watering flower from last, have to refill the water tank + */ +public class FloweringWater { + public int countRefill(int[] plants, int capacity1, int capacity2) { + int n = plants.length; + + int lo = 0; + int hi = n - 1; + + int count = 2; // fill both tanks initially + int w1 = capacity1; + int w2 = capacity2; + + while (lo < hi) { + if (plants[lo] > w1) { // no sufficient water, so needs to refill + w1 = capacity1; + count++; + } + w1 -= plants[lo]; // watering from start and remaining water + + if (plants[hi] > w2) { + w2 = capacity2; + count++; + } + w2 -= plants[hi]; + + lo++; + hi--; + } + + // if there is flower in between which both can water, then we can sum up + if ((n & 1) == 1) { + if (w1 + w2 < plants[lo]) count++; + } + return count; + } + + @Test + public void test() { + assertEquals(3, countRefill(new int[]{2, 4, 5, 1, 2}, 5, 7)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FourSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FourSum.java new file mode 100644 index 0000000..8f46f26 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FourSum.java @@ -0,0 +1,92 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + + +import org.junit.Test; + +import java.util.*; + +import static java.util.Arrays.asList; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums + * such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target. + *

+ * Note: + *

+ * The solution set must not contain duplicate quadruplets. + *

+ * Example: + *

+ * Given array nums = [1, 0, -1, 0, -2, 2], and target = 0. + *

+ * A solution set is: + * [ + * [-1, 0, 0, 1], + * [-2, -1, 1, 2], + * [-2, 0, 0, 2] + * ] + * + * https://leetcode.com/problems/4sum/ + */ +public class FourSum { + public List> fourSum(int[] nums, int target) { + + List> res = new ArrayList<>(); + + int n = nums.length; + + if (n < 3) return res; + + Arrays.sort(nums); + + Map>> map = new HashMap<>(); + + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + int sum = nums[i] + nums[j]; + + map.computeIfAbsent(sum, s -> new ArrayList<>()).add(Arrays.asList(i, j)); + } + } + + Set seen = new HashSet<>(); + + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + int x = nums[i] + nums[j]; + int y = target - x; + if (map.containsKey(y)) { + List> l = map.get(y); + + for (List p : l) { + int k = p.get(0); + int m = p.get(1); + + if (i == k || i == m || j == k || j == m) continue; // avoid same grouping + + List q = Arrays.asList(nums[i], nums[j], nums[k], nums[m]); + q.sort(Comparator.naturalOrder()); + String key = q.get(0) + "#" + q.get(1) + "#" + q.get(2) + "#" + q.get(3); + + if (seen.add(key)) { + res.add(q); + } + } + } + } + } + + return res; + } + + @Test + public void test() { + List> actual = fourSum(new int[]{1, 0, -1, 0, -2, 2}, 0); + List> expected = asList(asList(-2, -1, 1, 2), asList(-2, 0, 0, 2), asList(-1, 0, 0, 1)); + + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FruitsIntoBaskets.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FruitsIntoBaskets.java new file mode 100644 index 0000000..4bab684 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/FruitsIntoBaskets.java @@ -0,0 +1,63 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/fruit-into-baskets/ + */ +public class FruitsIntoBaskets { + public int totalFruit(int[] tree) { + if (tree.length <= 2) return tree.length; + + int n = tree.length; + + int start = 0; + + int b1 = tree[start]; + int b2 = tree[start]; + + int end = 1; + while (end < n) { + b2 = tree[end]; + if (b1 != b2) break; + end++; + } + + int max = end - start; + + int nextStart = end; + + while (end < tree.length) { + if (tree[end] == b1 || tree[end] == b2) { + end++; + } else { + max = Math.max(end - start, max); + // update b1, b2 + // update start and end + start = nextStart; + b1 = tree[start]; + b2 = tree[start]; + + end = start + 1; + while (end < n) { + b2 = tree[end]; + if (b1 != b2) break; + + end++; + } + + nextStart = end; + } + } + return Math.max(max, end - start); + } + + @Test + public void test() { + assertEquals(3, totalFruit(new int[] {0,1,2,2})); + assertEquals(4, totalFruit(new int[] {1,2,3,2,2})); + assertEquals(5, totalFruit(new int[] {3,3,3,1,2,1,1,2,3,3,4})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/HandOfStraight.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/HandOfStraight.java new file mode 100644 index 0000000..94b26d1 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/HandOfStraight.java @@ -0,0 +1,67 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + + +/** + * https://leetcode.com/problems/hand-of-straights/ + */ +public class HandOfStraight { + public boolean isNStraightHand(int[] hand, int W) { + + int n = hand.length; + + if (n % W != 0) return false; + + int k = n / W; + + int[] arr = new int[k]; + Arrays.fill(arr, W); + + Arrays.sort(hand); + + Map> vmap = new HashMap<>(); + + int curr = -1; + + for (int i = 0; i < n; i++) { + int num = hand[i]; + if (vmap.containsKey(num) && vmap.get(num).size() > 0) { + LinkedList indices = vmap.get(num); + int idx = indices.removeFirst(); + + arr[idx]--; + + if (arr[idx] > 0) + vmap.computeIfAbsent(num + 1, s -> new LinkedList<>()).add(idx); + } else { + curr++; + if (curr >= k) return false; + + arr[curr]--; + if (arr[curr] > 0) + vmap.computeIfAbsent(num + 1, s -> new LinkedList<>()).add(curr); + } + } + + for (int count : arr) { + if (count > 0) return false; + } + return true; + } + + @Test + public void test() { + assertTrue(isNStraightHand(new int[]{1, 2, 3, 6, 2, 3, 4, 7, 8}, 3)); + assertFalse(isNStraightHand(new int[]{1, 2, 3, 4, 5}, 3)); + assertTrue(isNStraightHand(new int[]{2, 1}, 2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/IntegerBreak.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/IntegerBreak.java new file mode 100644 index 0000000..ac7b698 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/IntegerBreak.java @@ -0,0 +1,51 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + +/** + * Given a positive integer n, break it into the sum of at least two positive integers and maximize the product of those integers. + * Return the maximum product you can get. + * + * Example 1: + * + * Input: 2 + * Output: 1 + * Explanation: 2 = 1 + 1, 1 × 1 = 1. + */ +public class IntegerBreak { + + @Test + public void test1() { + assertEquals(6, integerBreak(5)); + assertEquals(36, integerBreak(10)); + assertEquals(2, integerBreak(3)); + assertEquals(4, integerBreak(4)); + assertEquals(59049, integerBreak(30)); + assertEquals(1549681956, integerBreak(58)); + } + + // memoized version for breaking an integer + public int integerBreak(int n) { + if (n == 3) return 2; + int[] mem = new int[n + 1]; + Arrays.fill(mem, -1); + return intBreak(n, mem); + } + + private int intBreak(int n, int[] mem) { + if (n <= 2) return 1; + + if (mem[n] != -1) return mem[n]; + + int mul = 1; + for (int i = 1; i <= n; i++) { + mul = Math.max(mul, i * intBreak(n - i, mem)); + } + mem[n] = mul; + return mul; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/IntervalIntersection.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/IntervalIntersection.java new file mode 100644 index 0000000..46c0485 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/IntervalIntersection.java @@ -0,0 +1,81 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertArrayEquals; + +/** + * Given two lists of closed intervals, each list of intervals is pairwise disjoint and in sorted order. + *

+ * Return the intersection of these two interval lists. + *

+ * (Formally, a closed interval [a, b] (with a <= b) denotes the set of real numbers x with a <= x <= b. + * The intersection of two closed intervals is a set of real numbers that is either empty, or can be represented as a closed interval. + * For example, the intersection of [1, 3] and [2, 4] is [2, 3].) + *

+ *

+ *

+ * Example 1: + *

+ *

+ *

+ * Input: A = [[0,2],[5,10],[13,23],[24,25]], B = [[1,5],[8,12],[15,24],[25,26]] + * Output: [[1,2],[5,5],[8,10],[15,23],[24,24],[25,25]] + * Reminder: The inputs and the desired output are lists of Interval objects, and not arrays or lists. + */ +public class IntervalIntersection { + public int[][] intervalIntersection(int[][] A, int[][] B) { + int i = 0; + int j = 0; + + List l = new ArrayList<>(); + while (i < A.length && j < B.length) { + int[] a = A[i]; + int[] b = B[j]; + + // if either of start or end falls within the range of either interval, + // then add intersection + if (((b[0] <= a[0] && a[0] <= b[1]) || (b[0] <= a[1] && a[1] <= b[1])) || + (a[0] <= b[0] && b[0] <= a[1]) || (a[0] <= b[1] && b[1] <= a[1])) { + l.add(new int[]{Math.max(a[0], b[0]), Math.min(a[1], b[1])}); + } + + if (a[1] < b[1]) { + i++; + } else { + j++; + } + } + int[][] res = new int[l.size()][2]; + int idx = 0; + for (int[] m : l) { + res[idx++] = m; + } + return res; + } + + @Test + public void test() { + int[][] a = new int[][]{ + {3, 5}, + {9, 20} + }; + int[][] b = new int[][]{ + {4, 5}, + {7, 10}, + {11, 12}, + {14, 15}, + {16, 20} + }; + int[][] merged = intervalIntersection(a, b); + + assertArrayEquals(new int[]{4, 5}, merged[0]); + assertArrayEquals(new int[]{9, 10}, merged[1]); + assertArrayEquals(new int[]{11, 12}, merged[2]); + assertArrayEquals(new int[]{14, 15}, merged[3]); + assertArrayEquals(new int[]{16, 20}, merged[4]); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/KthLargestElement.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/KthLargestElement.java new file mode 100644 index 0000000..77bae08 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/KthLargestElement.java @@ -0,0 +1,69 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Random; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/kth-largest-element-in-an-array/ + */ +public class KthLargestElement { + private Random rnd = new Random(); + + public int findKthLargest(int[] nums, int k) { + // we do with ranking + int n = nums.length; + int left = 0; + int right = n - 1; + + while (left <= right) { + int pivotIdx = left + rnd.nextInt(right - left + 1); + + int pIdx = partition(nums, left, right, pivotIdx); + + if (pIdx == n - k) return nums[pIdx]; + + if (pIdx < n - k) { + left = pIdx + 1; + } else { + right = pIdx - 1; + } + } + return -1; + } + + private int partition(int[] nums, int l, int r, int p) { + + int i = l; + + + int pivot = nums[p]; + // put pivot to the end + swap(nums, p, r); + + for (int j = l; j < r; j++) { + if (nums[j] < pivot) { + swap(nums, i, j); + i++; + } + } + + swap(nums, r, i); + + return i; + } + + private void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + @Test + public void test() { +// assertEquals(4, findKthLargest(new int[] {3,2,3,1,2,4,5,5,6}, 4)); + assertEquals(5, findKthLargest(new int[] {3,2,3,1,2,4,5,5,6}, 2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LargestPlusSign.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LargestPlusSign.java new file mode 100644 index 0000000..cd48e5b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LargestPlusSign.java @@ -0,0 +1,72 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/largest-plus-sign/ + */ +public class LargestPlusSign { + public int orderOfLargestPlusSign(int N, int[][] mines) { + int[][] matrix = new int[N][N]; + for (int[] mine : mines) { + int r = mine[0]; + int c = mine[1]; + matrix[r][c] = 1; + } + + int[][] left = new int[N][N]; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (matrix[i][j] == 0) { + left[i][j] = (j > 0 ? left[i][j - 1] : 0) + 1; + } + } + } + + int[][] right = new int[N][N]; + for (int i = 0; i < N; i++) { + for (int j = N - 1; j >= 0; j--) { + if (matrix[i][j] == 0) { + right[i][j] = (j < N - 1 ? right[i][j + 1] : 0) + 1; + } + } + } + + int[][] top = new int[N][N]; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (matrix[i][j] == 0) + top[i][j] = (i > 0 ? top[i - 1][j] : 0) + 1; + } + + } + + int[][] bottom = new int[N][N]; + for (int i = N - 1; i >= 0; i--) { + for (int j = 0; j < N; j++) { + if (matrix[i][j] == 0) { + bottom[i][j] = (i < N - 1 ? bottom[i + 1][j] : 0) + 1; + } + } + } + + int order = 0; + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (matrix[i][j] == 0) { + int curr = Math.min(Math.min(left[i][j], right[i][j]), + Math.min(top[i][j], bottom[i][j])); + order = Math.max(order, curr); + } + } + } + return order; + } + + @Test + public void test() { + assertEquals(2, orderOfLargestPlusSign(5, new int[][]{{4, 2}})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LargestSubarrayLengthK.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LargestSubarrayLengthK.java new file mode 100644 index 0000000..68283f2 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LargestSubarrayLengthK.java @@ -0,0 +1,47 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; + +/** + * + * largest subarray is contiguous subarray whose first different element is larger than other subarray + * + * return largest subarray of length k from all contiguous subarray of length k from given array + */ +public class LargestSubarrayLengthK { + public int[] largestSubarray(int[] arr, int k) { // arr.length >= k + // find subarray of length k + // see if it is largest compared to temp_result + // keep on going until you have subarray + + int n = arr.length; + + int[] subarr = new int[k]; + + System.arraycopy(arr, 0, subarr, 0, k); + + for (int i = 1; i <= n - k; i++) { + boolean larger = false; + + for (int j = i, m = 0; j < i + k; j++, m++) { + if (arr[j] > subarr[m]) { + larger = true; + break; + } + } + + if (larger) { + System.arraycopy(arr, i, subarr, 0, k); + } + } + + return subarr; + } + + @Test + public void test() { + assertArrayEquals(new int[] {4, 3, 2, 5}, largestSubarray(new int[] {1, 4, 3, 2, 5}, 4)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestAbsoluteFilePath.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestAbsoluteFilePath.java new file mode 100644 index 0000000..e2988a4 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestAbsoluteFilePath.java @@ -0,0 +1,48 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/longest-absolute-file-path/ + */ +public class LongestAbsoluteFilePath { + public int lengthLongestPath(String input) { + if (input == null || input.length() == 0) return 0; + + Stack stack = new Stack<>(); + stack.push(0); + + int len = 0; + + for (String str: input.split("\n")) { + int level = str.lastIndexOf("\t") + 1; + + while (level + 1 < stack.size()) stack.pop(); + + int curr = stack.peek() + str.length() - level + 1; // remove /t, add / + stack.push(curr); + + if (str.contains(".")) len = Math.max(len, curr - 1); + } + + return len; + } + + @Test + public void test() { + assertEquals(0, lengthLongestPath("file")); + assertEquals(12, lengthLongestPath("dir\n file.txt")); + assertEquals(20, lengthLongestPath("dir\n\t file.txt\n\tfile2.txt")); + assertEquals(25, lengthLongestPath("file name with space.txt")); + assertEquals(8, lengthLongestPath("file.txt")); + assertEquals(0, lengthLongestPath("dir\n\tsubdir1\n\tsubdir2\n\t\tsubdir3")); + assertEquals(16, lengthLongestPath("dir\n file.txt")); + assertEquals(20, lengthLongestPath("dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext")); + assertEquals(20, lengthLongestPath("dir\n\tsubdir1\n\tsubdir2\n\t\tfile.ext")); + assertEquals(32, lengthLongestPath("dir\n\tsubdir1\n\t\tfile1.ext\n\t\tsubsubdir1\n\tsubdir2\n\t\tsubsubdir2\n\t\t\tfile2.ext")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestArithmeticSubseq.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestArithmeticSubseq.java new file mode 100644 index 0000000..62534c9 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestArithmeticSubseq.java @@ -0,0 +1,62 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/longest-arithmetic-subsequence-of-given-difference/ + */ +public class LongestArithmeticSubseq { + public int longestSubsequence(int[] arr, int difference) { + //1,5,7,8,5,3,4,2,1, d = -2 [arr[i] - arr[j] = d, arr[i] + d = arr[j]] + + /* + // Time O(n^2) + // Space O(n) + + int[] mem = new int[arr.length]; + Arrays.fill(mem, 1); + for (int i = 1; i < arr.length; i++) { + for (int j = 0; j < i; j++) { + if (arr[i] - arr[j] == difference) { + mem[i] = Math.max(mem[i], mem[j] + 1); + } + } + } + int len = mem[0]; + for (int i = 1; i < mem.length; i++) { + if (len < mem[i]) len = mem[i]; + } + return len; + + */ + + // Time O(n) + // Space O(n) + // d[i] = d[i-k] + 1 + Map map = new HashMap<>(); + + for (int i = 0; i < arr.length; i++) { + int count = map.getOrDefault(arr[i] - difference, 0) + 1; + map.put(arr[i], count); + } + + int len = Integer.MIN_VALUE; + for (int l: map.values()) { + if (l > len) len = l; + } + return len; + } + + @Test + public void test() { + assertEquals(4, longestSubsequence(new int[] {1,2,3,4}, 1)); + assertEquals(1, longestSubsequence(new int[] {1,3,5,7}, 1)); + assertEquals(4, longestSubsequence(new int[] {1,5,7,8,5,3,4,2,1}, -2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestCommonSubseq.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestCommonSubseq.java new file mode 100644 index 0000000..b51b347 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestCommonSubseq.java @@ -0,0 +1,60 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; + +/** + * Given two sequences of integers, A[i] and B[j], find the longest common subsequence and print it as a line of space-separated integers. + * If there are multiple common subsequences with the same maximum length, print any one of them. + *

+ * Sample Input + *

+ * 5 6 + * 1 2 3 4 1 + * 3 4 1 2 1 3 + * Sample Output + *

+ * 1 2 3 + *

+ *

+ * https://www.hackerrank.com/challenges/dynamic-programming-classics-the-longest-common-subsequence/problem + */ +public class LongestCommonSubseq { + public int[] longestCommonSubsequence(int[] a, int[] b) { + int[][] mem = new int[a.length + 1][b.length + 1]; + for (int i = 1; i <= a.length; i++) { + for (int j = 1; j <= b.length; j++) { + if (a[i - 1] == b[j - 1]) { + mem[i][j] = 1 + mem[i - 1][j - 1]; + } else { + mem[i][j] = Math.max(mem[i - 1][j], mem[i][j - 1]); + } + } + } + + int len = mem[a.length][b.length]; + int[] res = new int[len]; + int i = len - 1; + for (int r = mem.length - 1; r > 0; r--) { + for (int c = mem[0].length - 1; c > 0; c--) { + // if it is coming from diagonal, then add res[i--] = a[c] + while (c > 0 && mem[r][c] == mem[r][c - 1]) { + c--; + } + if (mem[r][c] == mem[r - 1][c - 1] + 1) { + res[i--] = a[c - 1]; + if (i < 0) return res; + } else { + r--; + } + } + } + return res; + } + + @Test + public void test() { + assertArrayEquals(new int[]{3, 4, 1}, longestCommonSubsequence(new int[]{3, 4, 1, 2, 1, 3}, new int[]{1, 2, 3, 4, 1})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestIncreasingSubsequence.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestIncreasingSubsequence.java new file mode 100644 index 0000000..be73795 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestIncreasingSubsequence.java @@ -0,0 +1,41 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; + +import static junit.framework.TestCase.*; + + +/** + * https://leetcode.com/problems/longest-increasing-subsequence/ + */ +public class LongestIncreasingSubsequence { + public int findNumberOfLIS(int[] nums) { + int len = Integer.MIN_VALUE; + int[] m = new int[nums.length]; + + Arrays.fill(m, 1); + + for (int i = 1; i < nums.length; i++) { + for (int j = 0; j < i; j++) { + if (nums[j] < nums[i]) { + m[i] = Math.max(m[i], m[j] + 1); + } + } + len = Math.max(len, m[i]); + } + + int count = 0; + + for (int n: m) { + if (n == len) count++; + } + return count; + } + + @Test + public void test1() { + assertEquals(2, findNumberOfLIS(new int[] {1,3,5,4,7})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestSubstrWORep.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestSubstrWORep.java new file mode 100644 index 0000000..8fde5eb --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestSubstrWORep.java @@ -0,0 +1,77 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/longest-substring-without-repeating-characters/ + */ +public class LongestSubstrWORep { + public int lengthOfLongestSubstring(String s) { + // use map to track index of that character, and if it there in map, + // then start looking into element next to it + + int[] indices = new int[256]; + Arrays.fill(indices, -1); + + int len = 0; + int start = 0; + + int i = 0; + while (i < s.length()) { + + char ch = s.charAt(i); + + int index = indices[ch]; + + if (i > start && index >= start) { + if (i - start > len) len = i - start; + + start = index + 1; + } + indices[ch] = i; + i++; + } + return Math.max(i - start, len); + + /* + Map map = new HashMap<>(); + int len = 0; + for (int i = 0; i < s.length(); i++) { + + char ch = s.charAt(i); + + if (map.containsKey(ch)) { + if (map.size() > len) len = map.size(); + i = map.get(ch); + map.clear(); + } else { + map.put(ch, i); + } + } + return Math.max(map.size(), len); + + */ + } + + @Test + public void test() { + + assertEquals(5, lengthOfLongestSubstring("anviaj")); + assertEquals(3, lengthOfLongestSubstring("dvdf")); + assertEquals(3, lengthOfLongestSubstring("pwwkew")); + assertEquals(3, lengthOfLongestSubstring("abcabcbb")); + assertEquals(1, lengthOfLongestSubstring("bbbbb")); + assertEquals(1, lengthOfLongestSubstring(" ")); + assertEquals(1, lengthOfLongestSubstring(" ")); + assertEquals(2, lengthOfLongestSubstring("abba")); + assertEquals(5, lengthOfLongestSubstring("qrsvbspk")); + assertEquals(2, lengthOfLongestSubstring("aab")); + assertEquals(2, lengthOfLongestSubstring("au")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestWordInDict.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestWordInDict.java new file mode 100644 index 0000000..ea3686c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/LongestWordInDict.java @@ -0,0 +1,47 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/longest-word-in-dictionary-through-deleting/ + */ +public class LongestWordInDict { + public String findLongestWord(String s, List d) { + String res = ""; + for (String word: d) { + if (canForm(word, s)) { + if (word.length() > res.length()) + res = word; + else if (word.length() == res.length() && word.compareTo(res) < 0) { + res = word; + } + } + } + return res; + } + + private boolean canForm(String word, String str) { + int i = 0; + int j = 0; + + while (i < word.length() && j < str.length()) { + if (word.charAt(i) == str.charAt(j)) { + i++; + j++; + } else { + j++; + } + } + return i == word.length(); + } + + @Test + public void test() { + assertEquals("apple", findLongestWord("abpcplea", Arrays.asList("ale","apple","monkey","plea"))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxConsecutivesIII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxConsecutivesIII.java new file mode 100644 index 0000000..cfb66cf --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxConsecutivesIII.java @@ -0,0 +1,73 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Given an array A of 0s and 1s, we may change up to K values from 0 to 1. + * + * Return the length of the longest (contiguous) subarray that contains only 1s. + * + * + * + * Example 1: + * + * Input: A = [1,1,1,0,0,0,1,1,1,1,0], K = 2 + * Output: 6 + * Explanation: + * [1,1,1,0,0,1,1,1,1,1,1] + * Bolded numbers were flipped from 0 to 1. The longest subarray is underlined. + * + * https://leetcode.com/problems/max-consecutive-ones-iii/ + */ +public class MaxConsecutivesIII { + /** + * Slide start based upon + * 1) if there is 1, then look for freeing atleast one 0, find start + * 2) if there is 0, then free 0, and increase start by 1 + * @param A + * @param K + * @return + */ + public int longestOnes(int[] A, int K) { + int count = 0; + int start = 0; // to track the start of looking potential range + int end = 0; // to track the end of A + + int remK = K; + while (end < A.length) { + if (A[end] == 1) end++; // we are still good to move ahead + else { + if (remK > 0) { + remK--; + end++; + } else { + count = Math.max(count, end - start); + if (A[start] == 1) { + // move start till remK > 0 + while (remK == 0) { + if (A[start] == 0) { + remK++; + } + start++; + } + } else { + remK++; + start++; + } + } + } + } + count = Math.max(count, end - start); + + return count; + } + + @Test + public void test() { + assertEquals(6, longestOnes(new int[] {1,1,1,0,0,0,1,1,1,1,0}, 2)); + assertEquals(10, longestOnes(new int[] {1,1,1,0,0,0,1,1,1,1,0}, 3)); + assertEquals(10, longestOnes(new int[] {0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1}, 3)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxPointsLine.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxPointsLine.java new file mode 100644 index 0000000..186328d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxPointsLine.java @@ -0,0 +1,67 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/max-points-on-a-line/ + */ +public class MaxPointsLine { + public int maxPoints(int[][] points) { + if (points.length <= 2) return points.length; + + int count = 0; + + for (int i = 0; i < points.length; i++) { + + Map map = new HashMap<>(); + + int samep = 1; + + for (int j = 0; j < points.length; j++) { + + if (i == j) continue; + + int[] p1 = points[i]; + int[] p2 = points[j]; + + if (p1[0] == p2[0] && p1[1] == p2[1]) { + samep++; + continue; + } + + int dy = p2[1] - p1[1]; + int dx = p2[0] - p1[0]; + + int gcd = gcd(dy, dx); + + String key = dx / gcd + "#" + dy / gcd; + + if (map.containsKey(key)) map.put(key, map.get(key) + 1); + else map.put(key, 2); + + count = Math.max(count, samep + map.get(key) - 1); + } + + count = Math.max(count, samep); + } + + return count; + } + + private int gcd(int a, int b) { + if (b == 0) return a; + return gcd(b, a % b); + } + + @Test + public void test() { + assertEquals(2, maxPoints(new int[][] { {0,0},{1,65536},{65536,0}})); + assertEquals(3, maxPoints(new int[][] { {4,0},{4,-1},{4,5}})); + } +} + diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxRectangleArea.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxRectangleArea.java new file mode 100644 index 0000000..549035f --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxRectangleArea.java @@ -0,0 +1,75 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + + +/** + * https://leetcode.com/problems/maximal-rectangle/ + */ +public class MaxRectangleArea { + /** + * Time O((mn)^2) + * Space O(1) + * + * @param matrix + * @return + */ + public int maximalRectangle(char[][] matrix) { + int m = matrix.length; + if (m == 0) return 0; + int n = matrix[0].length; + + int max = 0; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (matrix[i][j] == '1') { + // search for largest rectangle possible + // if at any point encountered 0, then discontinue + int len = 0; + int wid = n - j; + for (int r = 0; r < m - i; r++) { + if (matrix[r + i][j] == '0') break; + + for (int c = 0; c < wid; c++) { + if (matrix[r + i][c + j] == '0') { + max = Math.max(len * wid, max); + wid = Math.min(wid, c); + break; + } + } + len++; + } + max = Math.max(len * wid, max); + + } + } + } + return max; + } + + @Test + public void test() { + char[][] matrix = new char[][]{ + {'1', '0', '1', '0', '0'}, + {'1', '0', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '0', '0', '1', '0'} + }; + + assertEquals(6, maximalRectangle(matrix)); + } + + @Test + public void test2() { + char[][] matrix = new char[][]{ + {'1', '1', '1', '1', '1', '1', '1', '1'}, + {'1', '1', '1', '1', '1', '1', '1', '0'}, + {'1', '1', '1', '1', '1', '1', '1', '0'}, + {'1', '1', '1', '1', '1', '0', '0', '0'}, + {'0', '1', '1', '1', '1', '0', '0', '0'} + }; + assertEquals(21, maximalRectangle(matrix)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxSubArrWOneDeletion.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxSubArrWOneDeletion.java new file mode 100644 index 0000000..14afd54 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxSubArrWOneDeletion.java @@ -0,0 +1,48 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Maximum subarray sum with max one deletion allowed + * + * https://leetcode.com/problems/maximum-subarray-sum-with-one-deletion/ + */ +public class MaxSubArrWOneDeletion { + /** + * We only need to track two variables: the maximum sum we can get (with / without) a deletion. + * + * For the maximum without a deletion, it is purely Kadane's algorithm. + * + * For the maximum with a deletion, we can either discard current number, or, add current number to previous maximum with a deletion. + * + * @param arr + * @return + */ + public int maximumSum(int[] arr) { + if (arr.length == 0) return 0; + if (arr.length == 1) return arr[0]; + + int maxSum = arr[0]; + int currWO = arr[0]; // track sum without deletion i.e. Kadane's algorithm + int currWith = arr[0]; // track sum with deletion + + for (int i = 1; i < arr.length; i++) { + currWith = Math.max(currWith + arr[i], currWO); + + currWO = Math.max(arr[i], arr[i] + currWO); + + maxSum = Math.max(Math.max(currWith, currWO), maxSum); + } + + return maxSum; + } + + @Test + public void test() { + assertEquals(3, maximumSum(new int[] {1,-2,-2,3})); + assertEquals(4, maximumSum(new int[] {1,-2,0,3})); + assertEquals(-1, maximumSum(new int[] {-1,-1,-1,-1})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxSubmatrixSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxSubmatrixSum.java new file mode 100644 index 0000000..d2d804f --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaxSubmatrixSum.java @@ -0,0 +1,58 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/max-sum-of-rectangle-no-larger-than-k/ + */ +public class MaxSubmatrixSum { + public int maxSumSubmatrix(int[][] matrix, int k) { + int m = matrix.length; + if (m == 0) return 0; + int n = matrix[0].length; + + int[][] height = new int[m][n]; + height[0] = matrix[0]; + + for (int i = 1; i < m; i++) { + for (int j = 0; j < n; j++) { + height[i][j] = height[i - 1][j] + matrix[i][j]; + } + } + + int max = 0; + + for (int i = 0; i < m; i++) { + for (int j = i; j < m; j++) { + int[] curr = new int[n]; + if (i > 0) curr = height[i - 1]; + int currMax = maxSum(height[j], curr, k); + if (currMax <= k) { + max = Math.max(currMax, max); + } + + } + } + return max; + } + + private int maxSum(int[] height, int[] minus, int k) { + int max = 0; + int curr = 0; + + for (int i = 0; i < height.length; i++) { + int h = height[i] - minus[i]; + curr = Math.max(0, curr) + h; + if (curr <= k) max = Math.max(curr, max); + } + return max; + } + + @Test + public void test() { + int[][] matrix = new int[][] {{2,2,-1}}; + assertEquals(3, maxSumSubmatrix(matrix, 3)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaximumTime.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaximumTime.java new file mode 100644 index 0000000..700a58e --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MaximumTime.java @@ -0,0 +1,82 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * You are given a string that represents time in the format hh:mm. Some of the digits are blank (represented by ?). + * Fill in ? such that the time represented by this string is the maximum possible. Maximum time: 23:59, minimum time: 00:00. + * You can assume that input string is always valid. + * + * Example 1: + * + * Input: "?4:5?" + * Output: "14:59" + * Example 2: + * + * Input: "23:5?" + * Output: "23:59" + * Example 3: + * + * Input: "2?:22" + * Output: "23:22" + * Example 4: + * + * Input: "0?:??" + * Output: "09:59" + * Example 5: + * + * Input: "??:??" + * Output: "23:59" + */ +public class MaximumTime { + public String maxTime(String time) { + char[] arr = time.toCharArray(); + + if (arr[0] == '?') { + if (arr[1] == '?') { + arr[0] = '2'; + arr[1] = '3'; + } else { + if (arr[1] < '4') { + arr[0] = '2'; + } else { + arr[0] = '1'; + } + } + } + + if (arr[1] == '?') { + if (arr[0] == '2') { + arr[1] = '3'; + } else { + arr[1] = '9'; + } + } + + if (arr[3] == '?') { + if (arr[4] == '?') { + arr[3] = '5'; + arr[4] = '9'; + } else { + arr[3] = '5'; + } + } + + if (arr[4] == '?') { + arr[4] = '9'; + } + + return new String(arr); + } + + @Test + public void test() { + assertEquals("14:59", maxTime("?4:5?")); + assertEquals("23:59", maxTime("23:5?")); + assertEquals("23:22", maxTime("2?:22")); + assertEquals("09:59", maxTime("0?:??")); + assertEquals("23:59", maxTime("??:??")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MergeKStack.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MergeKStack.java new file mode 100644 index 0000000..dd8ef94 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MergeKStack.java @@ -0,0 +1,101 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Comparator; +import java.util.PriorityQueue; +import java.util.Stack; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + + +/** + * Merge three stacks into one. + * + * s1 = -5,1,2,3,5 + * s2 = -3,4,6,7 + * s3 = 1,5 + * + * output (return one stack) + * -5,-3,1,1,2,3,4,5,5,6,7 + */ +public class MergeKStack { + // n = number of elements in stacks + // Time O(n*logk) + // Space O(n) + public Stack mergeKStack(Stack[] stacks) { + int n = stacks.length; + + Stack[] reversed = new Stack[n]; + + for (int i = 0; i < reversed.length; i++) { + reversed[i] = reverse(stacks[i]); + } + + Stack merged = new Stack<>(); + + PriorityQueue pq = new PriorityQueue<>(Comparator.comparingInt(i -> reversed[i].peek())); // min heap; return index of stack with min val + + for (int i = 0; i < n; i++) { + pq.offer(i); + } + + while (!pq.isEmpty()) { + + int curr = pq.poll(); + merged.push(reversed[curr].pop()); + + if (!reversed[curr].isEmpty()) pq.add(curr); + + } + return merged; + } + + private Stack reverse(Stack stack) { + Stack reversed = new Stack<>(); + while (!stack.isEmpty()) { + reversed.push(stack.pop()); + } + return reversed; + } + + @Test + public void test() { + Stack s1 = new Stack<>(); + s1.push(-5); + s1.push(1); + s1.push(2); + s1.push(3); + s1.push(5); + + Stack s2 = new Stack<>(); + s2.push(-3); + s2.push(4); + s2.push(6); + s2.push(7); + + Stack s3 = new Stack<>(); + s3.push(1); + s3.push(5); + + Stack[] stacks = new Stack[]{s1, s2, s3}; + + Stack actual = mergeKStack(stacks); + + Stack expected = new Stack<>(); + expected.push(-5); + expected.push(-3); + expected.push(1); + expected.push(1); + expected.push(2); + expected.push(3); + expected.push(4); + expected.push(5); + expected.push(5); + expected.push(6); + expected.push(7); + + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinCostForTickets.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinCostForTickets.java new file mode 100644 index 0000000..ff256e2 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinCostForTickets.java @@ -0,0 +1,60 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/minimum-cost-for-tickets/ + */ +public class MinCostForTickets { + public int mincostTickets(int[] days, int[] costs) { + int[] mem = new int[days.length]; + + dfs(days, 0, costs, mem); + return mem[0]; + } + + private int dfs(int[] days, int idx, int[] costs, int[] mem) { + if (idx >= days.length) { + return 0; + } + + if (mem[idx] > 0) return mem[idx]; + + int single = costs[0] + dfs(days, idx + 1, costs, mem); // just moves to next index + + int i = idx + 1; + for (; i < days.length; i++) { + + if (days[i] >= days[idx] + 7) { + i--; + break; + } + } + + int week = costs[1] + dfs(days, i + 1, costs, mem); + + i = idx + 1; + for (; i < days.length; i++) { + if (days[i] >= days[idx] + 30) { + i--; + break; + } + } + int months = costs[2] + dfs(days, i + 1, costs, mem); + + mem[idx] = Math.min(single, Math.min(week, months)); + return mem[idx]; + } + + @Test + public void test1() { + assertEquals(11, mincostTickets(new int[] {1,4,6,7,8,20}, new int[] {2, 7, 15})); + } + + @Test + public void test2() { + assertEquals(17, mincostTickets(new int[] {1,2,3,4,5,6,7,8,9,10,30,31}, new int[] {2, 7, 15})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinDaysToBloom.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinDaysToBloom.java new file mode 100644 index 0000000..c975f57 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinDaysToBloom.java @@ -0,0 +1,88 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Given an array of roses. roses[i] means rose i will bloom on day roses[i]. Also given an int k, + * which is the minimum number of adjacent bloom roses required for a bouquet, and an int n, which is the number of bouquets we need. + * Return the earliest day that we can get n bouquets of roses. + *

+ * Example: + * Input: roses = [1, 2, 4, 9, 3, 4, 1], k = 2, n = 2 + * Output: 4 + * Explanation: + * day 1: [b, n, n, n, n, n, b] + * The first and the last rose bloom. + *

+ * day 2: [b, b, n, n, n, n, b] + * The second rose blooms. Here the first two bloom roses make a bouquet. + *

+ * day 3: [b, b, n, n, b, n, b] + *

+ * day 4: [b, b, b, n, b, b, b] + * Here the last three bloom roses make a bouquet, meeting the required n = 2 bouquets of bloom roses. So return day 4. + */ +public class MinDaysToBloom { + @Test + public void test() { + assertEquals(4, minDaysBloom(new int[]{1, 2, 4, 9, 3, 4, 1}, 2, 2)); + assertEquals(6, minDaysBloom(new int[]{1, 5, 6, 2}, 1, 4)); + assertEquals(1, minDaysBloom(new int[]{1, 1, 1, 1}, 4, 1)); + } + + public int minDaysBloom(int[] roses, int k, int n) { + int len = roses.length; + if (len == 0) return 0; + + int lo = min(roses); + int hi = max(roses); + + while (lo < hi) { + int mid = (lo + hi) / 2; + if (bouquets(roses, mid, k) < n) { + lo = mid + 1; + } else { + hi = mid; + } + } + + return lo; + } + + private int bouquets(int[] roses, int day, int k) { + int running = 0; + int count = 0; + + for (int i = 0; i < roses.length; i++) { + if (roses[i] < day) { + running++; + } + + if (running == k) { + count++; + running = 0; + } + } + + return count; + } + + private int min(int[] arr) { + int min = arr[0]; + + for (int i = 1; i < arr.length; i++) { + if (arr[i] < min) min = arr[i]; + } + return min; + } + + private int max(int[] arr) { + int max = arr[0]; + for (int i = 1; i < arr.length; i++) { + if (max < arr[i]) max = arr[i]; + } + return max; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinDifferenceServerLoads.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinDifferenceServerLoads.java new file mode 100644 index 0000000..08c0f80 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinDifferenceServerLoads.java @@ -0,0 +1,63 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * There are some processes that need to be executed. Amount of a load that process causes on a server that runs it, + * is being represented by a single integer. Total load caused on a server is the sum of the loads of all the processes that run on that server. + * You have at your disposal two servers, on which mentioned processes can be run. + * Your goal is to distribute given processes between those two servers in the way that, absolute difference of their loads will be minimized. + *

+ * Given an array of n integers, of which represents loads caused by successive processes, return the minimum absolute difference of server loads. + *

+ * Example 1: + *

+ * Input: [1, 2, 3, 4, 5] + * Output: 1 + * Explanation: + * We can distribute the processes with loads [1, 2, 4] to the first server and [3, 5] to the second one, + * so that their total loads will be 7 and 8, respectively, and the difference of their loads will be equal to 1. + */ +public class MinDifferenceServerLoads { + + public int distributeLoad(int[] loads) { + // b1 1 3 + // b2 2 4 + + // 1 2 3 4 5 + // 1 (2 3 4 5) [b1 = 1, b2 = 0] + + Map mem = new HashMap<>(); + return dfs(loads, 0, 0, 0, mem); + } + + private int dfs(int[] loads, int idx, int b1, int b2, Map mem) { + int diff = Math.abs(b1 - b2); + if (idx == loads.length) { + return diff; + } + + String key = idx + "#" + diff; + + if (!mem.containsKey(key)) { + + mem.put(key, Math.min(dfs(loads, idx + 1, b1 + loads[idx], b2, mem), + dfs(loads, idx + 1, b1, b2 + loads[idx], mem))); + } + + + return mem.get(key); + } + + @Test + public void test() { + assertEquals(1, distributeLoad(new int[]{1, 2, 3, 4, 5})); + assertEquals(1, distributeLoad(new int[]{1, 1, 1, 1, 1})); + assertEquals(0, distributeLoad(new int[]{10, 10, 9, 9 ,2})); // [10,10], [9,9,2] + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinNumberOfChairs.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinNumberOfChairs.java new file mode 100644 index 0000000..5f57a74 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinNumberOfChairs.java @@ -0,0 +1,69 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.PriorityQueue; + +import static org.junit.Assert.assertEquals; + +/** + * There are n guests who are invited to a party. The k-th guest will attend the party at time S[k] and leave the party at time E[k]. + * + * Given an integer array S and an integer array E, both of length n, return an integer denoting the minimum number of chairs + * you need such that everyone attending the party can sit down. + * + * Example: + * + * Input: S = [1, 2, 6, 5, 3], E = [5, 5, 7, 6, 8] + * Output: 3 + * Explanation: + * There are five guests attending the party. + * The 1st guest will arrive at time 1. We need one chair at time 1. + * The 2nd guest will arrive at time 2. There are now two guests at the party, so we need two chairs at time 2. + * The 5th guest will arrive at time 3. There are now three guests at the party, so we need three chairs at time 3. + * The 4th guest will arrive at time 5 and, at the same moment, the 1st and 2nd guests will leave the party. + * There are now two (the 4th and 5th) guests at the party, so we need two chairs at time 5. + * The 3rd guest will arrive at time 6, and the 4th guest will leave the party at the same time. + * There are now two (the 3rd and 5th) guests at the party, so we need two chairs at time 6. + * So we need at least 3 chairs. + */ +public class MinNumberOfChairs { + public int minNumberOfChairs(int[] S, int[] E) { + int n = S.length; + if (n == 0) return 0; + + int[][] intervals = new int[n][2]; + for (int i = 0; i < n; i++) { + intervals[i] = new int[]{S[i], E[i]}; + } + + Arrays.sort(intervals, (i1, i2) -> i1[0] - i2[0]); + + PriorityQueue pq = new PriorityQueue<>(); + pq.add(intervals[0][1]); + + int count = 1; + + for (int i = 1; i < n; i++) { + int[] curr = intervals[i]; + + int prevEnd = pq.peek(); + + if (prevEnd <= curr[0]) { // re-use + pq.poll(); + } else { + count++; + } + + pq.offer(curr[1]); + } + + return count; + } + + @Test + public void test() { + assertEquals(3, minNumberOfChairs(new int[] {1, 2, 6, 5, 3}, new int[] {5, 5, 7, 6, 8})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinSwapToMakeIncreasing.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinSwapToMakeIncreasing.java new file mode 100644 index 0000000..f887d66 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MinSwapToMakeIncreasing.java @@ -0,0 +1,58 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * We have two integer sequences A and B of the same non-zero length. + * + * We are allowed to swap elements A[i] and B[i]. Note that both elements are in the same index position in their respective sequences. + * + * At the end of some number of swaps, A and B are both strictly increasing. (A sequence is strictly increasing if and only if A[0] < A[1] < A[2] < ... < A[A.length - 1].) + * + * Given A and B, return the minimum number of swaps to make both sequences strictly increasing. It is guaranteed that the given input always makes it possible. + * + * Example: + * Input: A = [1,3,5,4], B = [1,2,3,7] + * Output: 1 + * Explanation: + * Swap A[3] and B[3]. Then the sequences are: + * A = [1, 3, 5, 7] and B = [1, 2, 3, 4] + * which are both strictly increasing. + * + * https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/ + */ +public class MinSwapToMakeIncreasing { + public int minSwap(int[] A, int[] B) { + int n = A.length; + + int[] fix = new int[n]; + int[] swap = new int[n]; + + fix[0] = 0; + swap[1] = 1; + + for (int i = 1; i < n; i++) { + if (A[i - 1] >= B[i] || B[i - 1] >= A[i]) { + fix[i] = fix[i - 1]; + swap[i] = swap[i - 1] + 1; + } else if (A[i - 1] >= A[i] || B[i - 1] >= B[i]) { + fix[i] = swap[i - 1]; + swap[i] = fix[i - 1] + 1; + } else { + int min = Math.min(fix[ i -1], swap[i - 1]); + fix[i] = min; + swap[i] = min + 1; + } + } + + return Math.min(swap[n - 1], fix[n - 1]); + } + + @Test + public void test() { + assertEquals(1, minSwap(new int[]{0, 4, 4, 5, 9}, new int[]{0, 1, 6, 8, 10})); + assertEquals(1, minSwap(new int[]{3, 3, 8, 9, 109}, new int[]{1, 7, 4, 6, 8})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MiniFallingPathSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MiniFallingPathSum.java new file mode 100644 index 0000000..800a465 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MiniFallingPathSum.java @@ -0,0 +1,64 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + + +/** + * https://leetcode.com/problems/minimum-falling-path-sum/ + */ +public class MiniFallingPathSum { + public int minFallingPathSum(int[][] A) { + int min = Integer.MAX_VALUE; + + int m = A.length; + int n = A[0].length; + + int[][] mem = new int[m][n]; + + mem[0] = A[0]; + + for (int r = 1; r < A.length; r++) { + + for (int i = 0; i < n; i++) { + int curr; + if (i == 0) { + curr = Math.min(mem[r - 1][i], mem[r - 1][i + 1]); + } else if (i == n - 1) { + curr = Math.min(mem[r - 1][i - 1], mem[r - 1][i]); + } else { + curr = Math.min(mem[r - 1][i - 1], Math.min(mem[r - 1][i], mem[r - 1][i + 1])); + } + mem[r][i] = curr + A[r][i]; + } + } + + int currMin = findMin(mem[m - 1]); + if (min > currMin) min = currMin; + + return min; + } + + private int findMin(int[] arr) { + int min = arr[0]; + + for (int i = 1; i < arr.length; i++) { + if (arr[i] < min) min = arr[i]; + } + + return min; + } + + @Test + public void test1() { + int[][] mat = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; + assertEquals(12, minFallingPathSum(mat)); + } + + @Test + public void test2() { + int[][] mat = {{-51, -35, 74}, {-62, 14, -53}, {94, 61, -10}}; + assertEquals(-98, minFallingPathSum(mat)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MiniVisitTime.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MiniVisitTime.java new file mode 100644 index 0000000..5255378 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MiniVisitTime.java @@ -0,0 +1,28 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/minimum-time-visiting-all-points/ + */ +public class MiniVisitTime { + public int minTimeToVisitAllPoints(int[][] points) { + int time = 0; + + int[] start = points[0]; // 1,1 + for (int i = 1; i < points.length; i++) { + int[] curr = points[i]; // 3,4 + + time += Math.max(Math.abs(start[0] - curr[0]), Math.abs(start[1] - curr[1])); + start = curr; + } + return time; + } + + @Test + public void test() { + assertEquals(7, minTimeToVisitAllPoints(new int[][]{{1, 1}, {3, 4}, {-1, 0}})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MissingNumber2.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MissingNumber2.java new file mode 100644 index 0000000..38d7cda --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MissingNumber2.java @@ -0,0 +1,77 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * 570. Find the Missing Number II + + * Giving a string with number from 1-n in random order, but miss 1 number.Find that number. + * + * Example + * Example1 + * + * Input: n = 20 and str = 19201234567891011121314151618 + * Output: 17 + * Explanation: + * 19'20'1'2'3'4'5'6'7'8'9'10'11'12'13'14'15'16'18 + * Example2 + * + * Input: n = 6 and str = 56412 + * Output: 3 + * Explanation: + * 5'6'4'1'2 + * Notice + * n <= 30 + * Data guarantees have only one solution + * + * + * https://www.lintcode.com/problem/find-the-missing-number-ii/description + */ +public class MissingNumber2 { + public int findMissing2(int n, String str) { + // 1 920123 1 9 20123 1 9 2 + // 19 20123 + // write your code here + List l = new ArrayList<>(); + dfs(n, str, l, 0, new ArrayList<>()); + + int res = n; + for (int i = 0; i < l.size(); i++) { + res ^= (i + 1) ^ l.get(i); + } + return res; + } + + private void dfs(int n, String str, List l, int start, List temp) { + if (str.length() == start) { + if (temp.size() == n - 1) { + l.clear(); + l.addAll(temp); + } + + return; + } + int val = 0; + for (int i = start; i < str.length(); i++) { + val = val * 10 + (str.charAt(i) - '0'); + if (temp.contains(val)) continue; + + if (val > 0 && val <= n) { + temp.add(val); + dfs(n, str, l, i + 1, temp); + temp.remove(temp.size() - 1); + } + } + } + + @Test + public void test() { + assertEquals(17, findMissing2(20, "19201234567891011121314151618")); + assertEquals(3, findMissing2(6, "56412")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MostWaterContainer.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MostWaterContainer.java new file mode 100644 index 0000000..a0f8cc3 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/MostWaterContainer.java @@ -0,0 +1,63 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Given n non-negative integers a1, a2, ..., an , where each represents a point at coordinate (i, ai). + * n vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). + * Find two lines, which together with x-axis forms a container, such that the container contains the most water. + * + * Note: You may not slant the container and n is at least 2. + * + * + * + * + * + * The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49. + * + * + * + * Example: + * + * Input: [1,8,6,2,5,4,8,3,7] + * Output: 49 + */ +public class MostWaterContainer { + public int maxArea(int[] height) { + // int max = 0; + // for (int i = 0; i < height.length - 1; i++) { + // for (int j = i + 1; j < height.length; j++) { + // int area = (j - i) * Math.min(height[i], height[j]); + // if (max < area) { + // max = area; + // } + // } + // } + // return max; + + int max = 0; + int start = 0; + int end = height.length - 1; + while(start < end) { + int area = (end - start) * Math.min(height[start], height[end]); + if (area > max) { + max = area; + } + + if (height[start] < height[end]) { + start++; + } else { + end--; + } + } + return max; + } + + @Test + public void test() { + assertEquals(100, maxArea(new int[] {1,8,6,100,100,4,8,3,7})); + assertEquals(49, maxArea(new int[] {1,8,6,2,5,4,8,3,7})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Multiplication.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Multiplication.java new file mode 100644 index 0000000..2d17fbd --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Multiplication.java @@ -0,0 +1,25 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +// Return 1 if multiplication is +ve, -1 if negative and 0 if 0 +public class Multiplication { + public int solution(int[] A) { + int neg = 0; + for (int a : A) { + if (a < 0) neg++; + if (a == 0) return 0; + } + + return neg % 2 == 0 ? 1 : -1; + } + + @Test + public void test() { + assertEquals(1, solution(new int[]{-1,2,3,-1})); + assertEquals(-1, solution(new int[]{-1,2,3,-1,-2})); + assertEquals(0, solution(new int[]{-1,2,3,-1,-2,0})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/NQueens.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/NQueens.java new file mode 100644 index 0000000..c406a46 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/NQueens.java @@ -0,0 +1,89 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +public class NQueens { + private int[][] mem; + private List> l ; + + private int n; + + public List> solveNQueens(int n) { + this.l = new ArrayList<>(); + this.mem = new int[n][n]; + this.n = n; + + solve(0, new ArrayList<>()); + + return l; + } + + private void solve(int r, List temp) { + + for (int c = 0; c < n; c++) { + + if (mem[r][c] == 0 && goodSpot(r, c)) { + mem[r][c] = 2; + StringBuilder sb = new StringBuilder(); + + for (int k = 0; k < c; k++) sb.append("."); + + sb.append("Q"); + + for (int k = c + 1; k < n; k++) sb.append("."); + + temp.add(sb.toString()); + + if (r == n - 1) { + l.add(new ArrayList<>(temp)); + } else { + + solve(r + 1, temp); + } + mem[r][c] = 0; + temp.remove(temp.size() - 1); + + } + + } + } + + private boolean goodSpot(int r, int c) { + for (int col = 0; col < n; col++) { + if (mem[r][col] != 0) return false; + } + + for (int row = 0; row < n; row++) { + if (mem[row][c] != 0) return false; + } + + // main diagoal + for (int row = r - 1, col = c - 1; row >= 0 && col >= 0; row--, col--) { + if (mem[row][col] != 0) return false; + } + for (int row = r + 1, col = c + 1; row < n && col < n; row++, col++) { + if (mem[row][col] != 0) return false; + } + // opposite diagonal + for (int row = r - 1, col = c + 1; row >= 0 && col < n; row--, col++) { + if (mem[row][col] != 0) return false; + } + for (int row = r + 1, col = c - 1; row < n && col >= 0; row++, col--) { + if (mem[row][col] != 0) return false; + } + return true; + } + + @Test + public void test1() { + List> expected = asList(asList(".Q..","...Q","Q...","..Q."),asList("..Q.","Q...","...Q",".Q..")); + assertThat(solveNQueens(4), is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/NQueensII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/NQueensII.java new file mode 100644 index 0000000..931ce92 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/NQueensII.java @@ -0,0 +1,85 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * The n-queens puzzle is the problem of placing n queens on an n×n chessboard such that no two queens attack each other. + * + * + * + * Given an integer n, return the number of distinct solutions to the n-queens puzzle. + * + * Example: + * + * Input: 4 + * Output: 2 + * Explanation: There are two distinct solutions to the 4-queens puzzle as shown below. + * [ + * [".Q..", // Solution 1 + * "...Q", + * "Q...", + * "..Q."], + * + * ["..Q.", // Solution 2 + * "Q...", + * "...Q", + * ".Q.."] + * ] + */ +public class NQueensII { + private int[][] mem; + private int count; + public int totalNQueens(int n) { + mem = new int[n][n]; + + totalNQueens(n, 0); + return count; + } + + private void totalNQueens(int n, int r) { + for (int c = 0; c < n; c++) { + if (mem[r][c] == 0 && goodSpot(r, c)) { + mem[r][c] = 2; + if (r == n - 1) { + count++; + } else { + totalNQueens(n, r + 1); + } + mem[r][c] = 0; + } + } + } + + private boolean goodSpot(int r, int c) { + for (int col = 0; col < mem[0].length; col++) { + if (mem[r][col] != 0) return false; + } + + for (int row = 0; row < mem.length; row++) { + if (mem[row][c] != 0) return false; + } + + // main diagoal + for (int row = r - 1, col = c - 1; row >= 0 && col >= 0; row--, col--) { + if (mem[row][col] != 0) return false; + } + for (int row = r + 1, col = c + 1; row < mem.length && col < mem.length; row++, col++) { + if (mem[row][col] != 0) return false; + } + // opposite diagonal + for (int row = r - 1, col = c + 1; row >= 0 && col < mem.length; row--, col++) { + if (mem[row][col] != 0) return false; + } + for (int row = r + 1, col = c - 1; row < mem.length && col >= 0; row++, col--) { + if (mem[row][col] != 0) return false; + } + return true; + } + + @Test + public void test1() { + assertEquals(2, totalNQueens(4)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OddEvenJump.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OddEvenJump.java new file mode 100644 index 0000000..9ac9dda --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OddEvenJump.java @@ -0,0 +1,60 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.TreeMap; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/odd-even-jump/ + */ +public class OddEvenJump { + public int oddEvenJumps(int[] A) { + int n = A.length; + + if (n == 0) return 0; + + int count = 0; // last element counts 1 + + boolean[] odd = new boolean[n]; // if even jump can be made from i + boolean[] even = new boolean[n]; // if odd jump can be made from i + + TreeMap map = new TreeMap<>(); + map.put(A[n - 1], n - 1); + + odd[n - 1] = true; + even[n - 1] = true; + + for (int i = n - 2; i >= 0; i--) { + int curr = A[i]; + + Integer lower = map.floorKey(curr); + Integer higher = map.ceilingKey(curr); + + if (lower != null) { // if lower value exists in forward dir, then should be able to make even jump, and odd jump after that + even[i] = odd[map.get(lower)]; + } + + if (higher != null) { + odd[i] = even[map.get(higher)]; + } + + map.put(curr, i); + } + + for (boolean b: odd) { // since jump start from odd i.e. 1 + if (b) count++; + } + + return count; + } + + @Test + public void test() { + assertEquals(2, oddEvenJumps(new int[]{10, 13, 12, 14, 15})); + assertEquals(3, oddEvenJumps(new int[]{2, 3, 1, 1, 4})); + assertEquals(3, oddEvenJumps(new int[]{5, 1, 3, 4, 2})); + assertEquals(6, oddEvenJumps(new int[]{1, 2, 3, 2, 1, 4, 4, 5})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OnesAndZeros.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OnesAndZeros.java new file mode 100644 index 0000000..c00139c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OnesAndZeros.java @@ -0,0 +1,89 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/ones-and-zeroes/ + */ +public class OnesAndZeros { + public int findMaxForm(String[] strs, int m, int n) { + int[][] mem = new int[m + 1][n + 1]; + + for (String str : strs) { + int ones = 0; + int zeros = 0; + + for (char ch : str.toCharArray()) { + if (ch == '0') zeros++; + else ones++; + } + + for (int i = m; i >= zeros; i--) { + for (int j = n; j >= ones; j--) { + + mem[i][j] = Math.max(mem[i][j], mem[i - zeros][j - ones] + 1); + + } + } + } + + return mem[m][n]; + } + /* + private int ans = 0; + public int findMaxForm(String[] strs, int m, int n) { + dfs(strs, m, n, 0); + return ans; + } + + private void dfs(String[] strs, int m, int n, int count) { + if (m < 0 || n < 0) return; + if (count > ans) ans = count; + + for (int i = 0; i < strs.length; i++) { + String[] rem = new String[strs.length - 1]; + for (int j = 0, k = 0; j < strs.length;j++) { + if (i == j) continue; + rem[k++] = strs[j]; + } + + int ones = 0; + int zeros = 0; + + for (char ch: strs[i].toCharArray()) { + if (ch == '0') zeros++; + else ones++; + } + + dfs(rem, m - zeros, n - ones, count + 1); + } + } + */ + + + @Test + public void test1() { + assertEquals(4, findMaxForm(new String[]{"10", "0001", "111001", "1", "0"}, 5, 3)); + } + + @Test + public void test2() { + assertEquals(2, findMaxForm(new String[]{"10", "0", "1"}, 1, 1)); + } + + @Test + public void test3() { + assertEquals(4, findMaxForm(new String[]{"0", "0", "1", "1"}, 2, 2)); + } + + @Test + public void test4() { + assertEquals(3, findMaxForm(new String[]{"10", "0001", "111001", "1", "0"}, 3, 4)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OpenLock.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OpenLock.java new file mode 100644 index 0000000..cdd43ec --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/OpenLock.java @@ -0,0 +1,68 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/open-the-lock/ + */ +public class OpenLock { + public int openLock(String[] deadends, String target) { + Set s = new HashSet<>(); + Collections.addAll(s, deadends); + + Queue q = new LinkedList<>(); + q.add("0000"); + + Set checked = new HashSet<>(); + + int step = 0; + while (!q.isEmpty()) { + int size = q.size(); + for (int i = 0; i < size; i++) { + String str = q.poll(); + if (target.equals(str)) return step; + + if (s.contains(str) || checked.contains(str)) continue; + + checked.add(str); + + for (int j = 0; j < 4; j++) { + char curr = str.charAt(j); + char left = (char) (curr - 1); + if (curr - '0' - 1 == -1) { + // set 9 + left = '9'; + } + // rotate left + + q.add(str.substring(0, j) + left + str.substring(j + 1)); + // rotate right + char right = (char) (curr + 1); + if (curr - '0' + 1 == 10) { + right = '0'; + } + q.add(str.substring(0, j) + right + str.substring(j + 1)); + } + } + + step++; + } + return -1; + } + + @Test + public void test() { + String[] deadends = new String[]{"0201", "0101", "0102", "1212", "2002"}; + assertEquals(6, openLock(deadends, "0202")); + } + + @Test + public void test1() { + String[] deadends = new String[] {"8888"}; + assertEquals(1, openLock(deadends, "0009")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Palindrome.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Palindrome.java index 5ae0ad9..7407d88 100644 --- a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Palindrome.java +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Palindrome.java @@ -18,7 +18,7 @@ public void testIsPalindrome() { assertFalse(isPalindrome(122321)); } - public static boolean isPalindrome(int x) { + public boolean isPalindrome(int x) { int originalVal = x; int reversedX = 0; while(x != 0) { @@ -27,4 +27,46 @@ public static boolean isPalindrome(int x) { } return originalVal == reversedX; } + + public boolean isPalindrome(String s) { + if (s.isEmpty()) return true; + int start = 0; + int end = s.length() - 1; + + while (start <= end) { + char startChar = s.charAt(start); + char endChar = s.charAt(end); + + // startChar is lowercase + if (startChar >= 'a' && startChar <= 'z') { + startChar = (char)('A' + (startChar - 'a')); + } + + if (endChar >= 'a' && endChar <= 'z') { + endChar = (char)('A' + (endChar - 'a')); + } + + if ((startChar < 'A' || startChar > 'Z') && (startChar < '0' || startChar > '9')) { + start++; + continue; + } + + if ((endChar < 'A' || endChar > 'Z') && (endChar < '0' || endChar > '9')) { + end--; + continue; + } + + if (startChar != endChar) { + return false; + } + start++; + end--; + } + return true; + } + + @Test + public void test() { + assertTrue(isPalindrome("A man, a plan, a canal: Panama")); + } } diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PalindromePartitionIII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PalindromePartitionIII.java new file mode 100644 index 0000000..4fd1bd9 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PalindromePartitionIII.java @@ -0,0 +1,126 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/palindrome-partitioning-iii/ + */ +public class PalindromePartitionIII { + private Map map = new HashMap<>(); + + public int palindromePartition(String s, int k) { + + for (int start = 0; start < s.length(); start++) { + for (int end = start; end < s.length(); end++) { + String sub = s.substring(start, end + 1); + if (!map.containsKey(sub)) { + map.put(sub, makePalindrome(sub)); + } + } + } + + Map mem = new HashMap<>(); + split(s, k, mem); + + return mem.get(new MemKey(s, k)); + } + + private int split(String s, int k, Map mem) { + + if (s.length() <= 1) { + return 0; + } + + MemKey key = new MemKey(s, k); + + if (mem.containsKey(key)) { + return mem.get(key); + } + + if (k == 1) { + int count = map.get(s); + mem.put(key, count); + return count; + } + + int count = Integer.MAX_VALUE; + for (int i = 1; i < s.length(); i++) { + String first = s.substring(0, i); + String second = s.substring(i); + + count = Math.min(count, map.get(first) + split(second, k - 1, mem)); + } + mem.put(key, count); + return count; + } + + private int makePalindrome(String s) { + int start = 0; + int end = s.length() - 1; + + int count = 0; + while (start < end) { + if (s.charAt(start) != s.charAt(end)) { + count++; + } + start++; + end--; + } + return count; + } + + class MemKey { + String str; + int k; + MemKey(String str, int k) { + this.str = str; + this.k = k; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MemKey)) return false; + MemKey that = (MemKey) obj; + + return this.str.equals(that.str) && this.k == that.k; + } + + @Override + public int hashCode() { + int code = 17; + code = code * 17 + this.str.hashCode(); + code = code * 17 + this.k; + return code; + } + } + + @Test + public void test1() { + assertEquals(0, palindromePartition("aabbcc", 3)); + } + + @Test + public void test2() { + assertEquals(0, palindromePartition("aabbaa", 1)); + } + + @Test + public void test3() { + assertEquals(1, palindromePartition("abc", 2)); + } + + @Test + public void test4() { + assertEquals(0, palindromePartition("faaglagedtwnejzpuarkgwgoefwra", 27)); + } + + @Test + public void test5() { + assertEquals(6, palindromePartition("spsvmwkvwyfnrrfklevvyxsayc", 6)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PartitionWEqualSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PartitionWEqualSum.java new file mode 100644 index 0000000..92a539f --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PartitionWEqualSum.java @@ -0,0 +1,102 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +/** + * Given an array A of integers, return true if and only if we can partition the array into three non-empty parts with equal sums. + *

+ * Formally, we can partition the array if we can find indexes i+1 < j with (A[0] + A[1] + ... + A[i] == A[i+1] + A[i+2] + ... + A[j-1] == A[j] + A[j-1] + ... + A[A.length - 1]) + *

+ *

+ *

+ * Example 1: + *

+ * Input: [0,2,1,-6,6,-7,9,1,2,0,1] + * Output: true + * Explanation: 0 + 2 + 1 = -6 + 6 - 7 + 9 + 1 = 2 + 0 + 1 + */ +public class PartitionWEqualSum { + /** + * O(n^2) - time + * @param arr + * @return + */ + public boolean canThreePartsEqualSum(int[] arr) { + // find sum to index i, see if rest of array can be divided into two to find target sum + int sum = 0; + for (int n : arr) { + sum += n; + } + + int p1 = 0; + + for (int i = 0; i < arr.length - 1; i++) { + p1 += arr[i]; + sum -= arr[i]; + if (canTwoPartsEqualSum(arr, i + 1, p1, sum)) return true; + } + + return false; + } + + private boolean canTwoPartsEqualSum(int[] arr, int startIdx, int target, int sum) { + int p2 = 0; + for (int i = startIdx; i < arr.length; i++) { + p2 += arr[i]; + sum -= arr[i]; + if (p2 == target && sum == target) return true; + } + return false; + } + + @Test + public void testCanThreePartsEqualSum() { + assertTrue(canThreePartsEqualSum(new int[]{0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1})); + assertFalse(canThreePartsEqualSum(new int[]{0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1})); + assertTrue(canThreePartsEqualSum(new int[]{3, 3, 6, 5, -2, 2, 5, 1, -9, 4})); + assertTrue(canThreePartsEqualSum(new int[]{18, 12, -18, 18, -19, -1, 10, 10})); + assertTrue(canThreePartsEqualSum(new int[]{2, 8, 15, -5, 0, 9, -3, 4})); + + } + + + /** + * O(n) - time + * @param arr + * @return + */ + public boolean canThreePartsEqualSumBetter(int[] arr) { + // find sum to index i, see if rest of array can be divided into two to find target sum + int sum = 0; + for (int n : arr) { + sum += n; + } + + if (sum % 3 != 0) return false; + + int partSum = sum / 3; + int tempSum = 0; + int count = 0; + for (int n: arr) { + tempSum += n; + if (partSum == tempSum) { + count++; + tempSum = 0; + } + } + return count == 3; + } + + @Test + public void testCanThreePartsEqualSumBetter() { + assertTrue(canThreePartsEqualSumBetter(new int[]{0, 2, 1, -6, 6, -7, 9, 1, 2, 0, 1})); + assertFalse(canThreePartsEqualSumBetter(new int[]{0, 2, 1, -6, 6, 7, 9, -1, 2, 0, 1})); + assertTrue(canThreePartsEqualSumBetter(new int[]{3, 3, 6, 5, -2, 2, 5, 1, -9, 4})); + assertTrue(canThreePartsEqualSumBetter(new int[]{18, 12, -18, 18, -19, -1, 10, 10})); + assertTrue(canThreePartsEqualSumBetter(new int[]{2, 8, 15, -5, 0, 9, -3, 4})); + + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PascalTriangle.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PascalTriangle.java new file mode 100644 index 0000000..35c3e09 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PascalTriangle.java @@ -0,0 +1,48 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; +import org.w3c.dom.ls.LSException; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + + +public class PascalTriangle { + public List> generate(int numRows) { + + List> r = new ArrayList<>(); + if (numRows == 0) return r; + + List r1 = Collections.singletonList(1); + r.add(r1); + if (numRows == 1) { + return r; + } + + for (int rn = 2; rn <= numRows; rn++) { + List row = new ArrayList<>(); + row.add(1); + for (int i = 1, s = 0; i < rn - 1; i++, s++) { + int ith = r.get(rn - 2).get(s) + r.get(rn - 2).get(s + 1); + row.add(ith); + } + row.add(1); + r.add(row); + } + return r; + } + + @Test + public void testGenerate() { + List> actual = generate(5); + List> expected = asList(asList(1), asList(1,1), asList(1,2,1),asList(1,3,3,1), asList(1,4,6,4,1)); + assertThat(actual, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PossibleBipartition.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PossibleBipartition.java new file mode 100644 index 0000000..a913f27 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/PossibleBipartition.java @@ -0,0 +1,72 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +import static org.junit.Assert.assertFalse; + + +/** + * https://leetcode.com/problems/possible-bipartition/submissions/ + */ +public class PossibleBipartition { + public boolean possibleBipartition(int N, int[][] dislikes) { + + // create graph with people disliking each other + List[] graph = new ArrayList[N + 1]; + for (int i = 0; i <= N; i++) { + graph[i] = new ArrayList<>(); + } + + for (int[] dislike: dislikes) { + int u = dislike[0]; + int v = dislike[1]; + graph[u].add(v); + graph[v].add(u); + } + + + // to track if particular person node has been visited + int[] visited = new int[N + 1]; + Arrays.fill(visited, -1); + + // this is to make sure all graphs in forests has been visited + for (int i = 1; i <= N; i++) { + if (visited[i] == -1) { + Stack stack = new Stack<>(); + stack.push(new int[] {i, 0}); // stack [vertex,odd or even] + + while (!stack.isEmpty()) { + int[] pair = stack.pop(); + int curr = pair[0]; + int status = pair[1]; + + List neb = graph[curr]; + for (int n: neb) { + // if not visited, add into stack with opposite status + if (visited[n] == -1) { + visited[n] = status == 0 ? 1 : 0; + stack.push(new int[] {n, visited[n]}); + } else { + if (visited[n] == status) return false; + } + } + } + } + } + + return true; + } + + @Test + public void test() { + int[][] dislikes = new int[][] { + {1,2},{3,4},{4,5},{3,5} + }; + assertFalse(possibleBipartition(5, dislikes)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RLEIteratorTest.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RLEIteratorTest.java new file mode 100644 index 0000000..6035b6d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RLEIteratorTest.java @@ -0,0 +1,78 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/rle-iterator/submissions/ + */ +public class RLEIteratorTest { + + @Test + public void test1() { + RLEIterator iterator = new RLEIterator(new int[] {3, 8, 0, 9 , 2, 5}); + assertEquals(8, iterator.next(2)); + assertEquals(8, iterator.next(1)); + assertEquals(5, iterator.next(1)); + assertEquals(-1, iterator.next(2)); + } + + @Test + public void test2() { + //[[[811,903,310,730,899,684,472,100,434,611]],[358],[345],[154],[265],[73],[220],[138],[4],[170],[88]] + RLEIterator iterator = new RLEIterator(new int[] {811,903,310,730,899,684,472,100,434,611}); + assertEquals(903, iterator.next(358)); + assertEquals(903, iterator.next(345)); + assertEquals(730, iterator.next(154)); + assertEquals(684, iterator.next(265)); + assertEquals(684, iterator.next(73)); + assertEquals(684, iterator.next(220)); + assertEquals(684, iterator.next(138)); + assertEquals(684, iterator.next(4)); + assertEquals(684, iterator.next(170)); + assertEquals(684, iterator.next(88)); + //[null,903,903,730,684,684,684,684,684,684,684] + } + +} + +class RLEIterator { + private int[] A; // 3, 8, 0, 9 , 2, 5 + private int p; + public RLEIterator(int[] A) { + this.A = A; + } + + public int next(int n) { + if (p >= A.length) return -1; // p = 0 + + while (p < A.length && A[p] == 0) { + if (A[p] == 0) { + p = p + 2; + } + } + + if (p >= A.length) return -1; + + // 1 + int rem = A[p] - n; + while (p < A.length) { + + if (rem < 0) { + A[p] = 0; + p = p + 2; + if (p < A.length) { + rem += A[p]; + } + } else { + A[p] = rem; // A[0] = 1 + break; + } + } + + if (p >= A.length) return -1; + + return A[p + 1]; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RandomPickIndex.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RandomPickIndex.java new file mode 100644 index 0000000..ec57fc7 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RandomPickIndex.java @@ -0,0 +1,52 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.CoreMatchers.anyOf; + +/** + * https://leetcode.com/problems/random-pick-index/ + */ +class Solution { + + private Random rand; + + /** + * nums[i] -> [i, j, k] + */ + private Map> map; + public Solution(int[] nums) { + this.map = new HashMap<>(); + + for (int i = 0; i < nums.length; i++) { + if (!map.containsKey(nums[i])) { + map.put(nums[i], new ArrayList<>()); + } + List l = map.get(nums[i]); + l.add(i); + } + this.rand = new Random(); + } + + public int pick(int target) { + List l = map.get(target); + + int idx = rand.nextInt(l.size()); + + return l.get(idx); + + } + +} + +public class RandomPickIndex { + @Test + public void test1() { + Solution random = new Solution(new int[]{1, 2, 3, 3, 3}); + assertThat(random.pick(3), anyOf(is(2), is(3), is(4))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RandomizedSetTest.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RandomizedSetTest.java new file mode 100644 index 0000000..1e62c10 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RandomizedSetTest.java @@ -0,0 +1,99 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.Random; + +import static org.junit.Assert.*; + +/** + * Design a data structure that supports all following operations in average O(1) time. + * + * insert(val): Inserts an item val to the set if not already present. + * remove(val): Removes an item val from the set if present. + * getRandom: Returns a random element from current set of elements. Each element must have the same probability of being returned. + * + * + * https://leetcode.com/problems/insert-delete-getrandom-o1/ + */ +public class RandomizedSetTest { + @Test + public void test1() { + RandomizedSet set = new RandomizedSet(); + assertTrue(set.insert(0)); + assertTrue(set.insert(1)); + assertTrue(set.remove(0)); + assertTrue(set.insert(2)); + assertTrue(set.remove(1)); + } + + @Test + public void test2() { + RandomizedSet set = new RandomizedSet(); + assertTrue(set.insert(0)); + assertTrue(set.remove(0)); + assertTrue(set.insert(-1)); + assertFalse(set.remove(0)); + + assertEquals(-1, set.getRandom()); + } + + @Test + public void test3() { + RandomizedSet set = new RandomizedSet(); + assertTrue(set.insert(3)); + assertFalse(set.insert(3)); + assertTrue(set.insert(1)); + assertTrue(set.remove(3)); + assertTrue(set.insert(0)); + assertTrue(set.remove(0)); + } +} + +class RandomizedSet { + + private Map map; + private LinkedList list; + private Random rand; + /** Initialize your data structure here. */ + public RandomizedSet() { + this.list = new LinkedList<>(); + this.map = new HashMap<>(); + this.rand = new Random(); + } + + /** Inserts a value to the set. Returns true if the set did not already contain the specified element. */ + public boolean insert(int val) { + if (map.containsKey(val)) { + return false; + } + int size = list.size(); + map.put(val, size); + list.addLast(val); + return true; + } + + /** Removes a value from the set. Returns true if the set contained the specified element. */ + public boolean remove(int val) { + if (map.containsKey(val)) { + int idx = map.get(val); + int last = list.removeLast(); + if (last != val) { + list.set(idx, last); + map.put(last, idx); + } + map.remove(val); + return true; + } + return false; + } + + /** Get a random element from the set. */ + public int getRandom() { + int idx= rand.nextInt(list.size()); + return list.get(idx); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RemoveElement.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RemoveElement.java new file mode 100644 index 0000000..a14632c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RemoveElement.java @@ -0,0 +1,60 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Given an array nums and a value val, remove all instances of that value in-place and return the new length. + * + * Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory. + * + * The order of elements can be changed. It doesn't matter what you leave beyond the new length. + * + * Example 1: + * + * Given nums = [3,2,2,3], val = 3, + * + * Your function should return length = 2, with the first two elements of nums being 2. + * + * It doesn't matter what you leave beyond the returned length. + * + */ +public class RemoveElement { + public int removeElement(int[] nums, int val) { + int i = 0; // index to track target + int j = 0; // index to track non-target + int count = 0; + while (i < nums.length && j < nums.length) { + if (nums[i] == val) { + if (i < j && nums[j] != val) { + swap(nums, i, j); + i++; + } else { + j++; + } + } else { + i++; + j++; + } + } + + for (int n: nums) { + if (n == val) break; + count++; + } + return count; + } + + private void swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + + @Test + public void test() { + int[] arr = new int[] {0,1,2,2,3,0,4,2}; + assertEquals(5, removeElement(arr, 2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RemoveKDigits.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RemoveKDigits.java new file mode 100644 index 0000000..350fce8 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RemoveKDigits.java @@ -0,0 +1,60 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/remove-k-digits/ + */ +public class RemoveKDigits { + /** + * if encounter digits less than previous, then remove all of them until it becomes non-decreasing + * + * @param num + * @param k + * @return + */ + public String removeKdigits(String num, int k) { + Stack s = new Stack<>(); + for (char n: num.toCharArray()) { + + while (k > 0 && !s.isEmpty() && s.peek() > n) { + s.pop(); + k--; + } + if (s.isEmpty()) { + if (n != '0') + s.push(n); + } else { + s.push(n); + } + } + + while (k > 0 && !s.isEmpty()) { + s.pop(); + k--; + } + + StringBuilder sb = new StringBuilder(); + while (!s.isEmpty()) { + sb.append(s.pop()); + } + + return sb.length() > 0 ? sb.reverse().toString(): "0"; + } + + @Test + public void test() { + assertEquals("0", removeKdigits("10", 2)); + assertEquals("1219", removeKdigits("1432219", 3)); + assertEquals("200", removeKdigits("10200", 1)); + assertEquals("0", removeKdigits("10", 2)); + assertEquals("123450", removeKdigits("1234567890", 4)); + assertEquals("0", removeKdigits("1234", 4)); + assertEquals("0", removeKdigits("9", 1)); + assertEquals("1111", removeKdigits("1111111", 3)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ReorganizeString.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ReorganizeString.java new file mode 100644 index 0000000..d1aad4d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ReorganizeString.java @@ -0,0 +1,53 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.PriorityQueue; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/reorganize-string/ + */ +public class ReorganizeString { + public String reorganizeString(String S) { + int n = S.length(); + + int[] count = new int[26]; + + for (char ch: S.toCharArray()) { + count[ch - 'a']++; + } + + PriorityQueue pq = new PriorityQueue<>((e1, e2) -> e1[1] == e2[1] ? e1[0] - e2[0] : e2[1] - e1[1]); + + for (int i = 0; i < 26; i++) { + if (count[i] > 0) { + if (count[i] > (n + 1) / 2) return ""; + pq.offer(new int[]{i, count[i]}); + } + } + + StringBuilder sb = new StringBuilder(); + + while (pq.size() >= 2) { + int[] p = pq.poll(); + int[] q = pq.poll(); + + sb.append((char) ('a' + p[0])); + sb.append((char) ('a' + q[0])); + + if (--p[1] > 0) pq.offer(p); + if (--q[1] > 0) pq.offer(q); + } + if (pq.size() > 0) sb.append((char) ('a' + pq.poll()[0])); + + return sb.toString(); + } + + @Test + public void test() { + assertEquals("aba", reorganizeString("aab")); + assertEquals("", reorganizeString("aaab")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ReversePairs.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ReversePairs.java new file mode 100644 index 0000000..6d92f3b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ReversePairs.java @@ -0,0 +1,78 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * pair of indices (i, j) are important pairs such that i < j & nums[i] > 2 * num[j] + * + * Return count of all those pairs + * + * https://leetcode.com/problems/reverse-pairs/ + */ +public class ReversePairs { + + public int reversePairs(int[] nums) { + int n = nums.length; + return mergeSort(nums, 0, n - 1); + } + + private int mergeSort(int[] nums, int lo, int hi) { + if (lo >= hi) return 0; + int mid = lo + (hi - lo) / 2; + int count = mergeSort(nums, lo, mid) + mergeSort(nums, mid + 1, hi); + + int p = lo; + int q = mid + 1; + + while (p <= mid && q <= hi) { + if (nums[p] > 2L * nums[q]) { + count += (mid - p + 1); + q++; + } else { + p++; + } + } + + merge(nums, lo, mid, hi); + + return count; + } + + private void merge(int[] nums, int lo, int mid, int hi) { + int len = hi - lo + 1; + int[] copy = new int[len]; + + int p = lo; + int q = mid + 1; + + int i = 0; + + while (p <= mid && q <= hi) { + if (nums[p] < nums[q]) { + copy[i++] = nums[p++]; + } else { + copy[i++] = nums[q++]; + } + } + + while (p <= mid) { + copy[i++] = nums[p++]; + } + + while (q <= hi) { + copy[i++] = nums[q++]; + } + + System.arraycopy(copy, 0, nums, lo, len); + } + + + @Test + public void test() { + assertEquals(4, reversePairs(new int[] {5,4,3,2,1})); + assertEquals(2, reversePairs(new int[] {1,3,2,3,1})); + assertEquals(3, reversePairs(new int[] {2,4,3,5,1})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RotateString.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RotateString.java new file mode 100644 index 0000000..e0a8e3d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/RotateString.java @@ -0,0 +1,63 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +public class RotateString { + public boolean rotateString(String A, String B) { + if (A.length() != B.length()) return false; + int[] lps = findLps(A); + + int i = 0; + int j = 0; + while (j < A.length() && i < B.length()) { + // A - pattern + // B - text + if (A.charAt(j) == B.charAt(i)) { + i++; + j++; + } else { + if (j == 0) { + i++; + } else { + j = lps[j - 1]; + } + } + } + + return A.substring(j).equals(B.substring(0, B.length() - j)); + + } + + private int[] findLps(String str) { + int[] lps = new int[str.length()]; + + int j = 0; + int i = 1; + while (i < str.length()) { + if (str.charAt(i) == str.charAt(j)) { + j++; + lps[i] = j; + i++; + } else if (str.charAt(i) != str.charAt(j) && j != 0) { + j = lps[j - 1]; + } else { + lps[i] = 0; + i++; + } + } + + return lps; + } + + @Test + public void test() { + assertTrue(rotateString("abcde", "cdeab")); + assertTrue(rotateString("abcde", "bcdea")); + assertTrue(rotateString("abcde", "abcde")); + assertFalse(rotateString("abcde", "abcdf")); + assertTrue(rotateString("bbbacddceeb", "ceebbbbacdd")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ScoreOfParentheses.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ScoreOfParentheses.java new file mode 100644 index 0000000..31d5c65 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ScoreOfParentheses.java @@ -0,0 +1,50 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/score-of-parentheses/ + */ +public class ScoreOfParentheses { + public int scoreOfParentheses(String S) { + // at i, open = 1, go on till open = 0 at j + // sofar = 2 * substring (i + 1, j) + // ans += sofar + + int n = S.length(); + + if (n == 0) return 0; + + if (n == 2) return 1; + + int ans = 0; + + for (int i = 0; i < n;) { + int open = 1; + int j = i + 1; + while(j < n) { + if (S.charAt(j) == '(') open++; + else { + open--; + if (open == 0) break; + } + j++; + } + String rem = S.substring(i + 1, j); + ans += (rem.length() == 0 ? 1 : 2 * scoreOfParentheses(rem)); + i = j + 1; + } + + return ans; + } + + @Test + public void test() { + assertEquals(2, scoreOfParentheses("()()")); + assertEquals(2, scoreOfParentheses("(())")); + assertEquals(3, scoreOfParentheses("()(())")); + assertEquals(6, scoreOfParentheses("(()(()))")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Search2DMatrix.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Search2DMatrix.java new file mode 100644 index 0000000..475cecb --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/Search2DMatrix.java @@ -0,0 +1,121 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties: + * + * - Integers in each row are sorted from left to right. + * - The first integer of each row is greater than the last integer of the previous row. + */ +public class Search2DMatrix { + public boolean searchMatrix(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false; + + // int[] firstRow = matrix[0]; + // int[] lastRow = matrix[matrix.length - 1]; + + // if (firstRow) + // find row in which target falls using bs + // search target in that row + int start = 0; + int end = matrix.length - 1; + + while (start <= end) { + int mid = start + (end - start) / 2; + int[] row = matrix[mid]; + + if (row[0] <= target && target <= row[row.length - 1]) { + return bs(row, target); + } else if (row[0] > target) { + end = mid - 1; + } else { + start = mid + 1; + } + } + + return false; + } + + private boolean bs(int[] arr, int target) { + int start = 0; + int end = arr.length - 1; + + while (start <= end) { + int mid = start + (end - start) / 2; + + if (arr[mid] == target) { + return true; + } else if (arr[mid] < target) { + start = mid + 1; + } else { + end = mid - 1; + } + } + return false; + } + + @Test + public void test1() { + int[][] matrix = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8,9}}; + assertTrue(searchMatrix(matrix, 3)); + assertTrue(searchMatrix(matrix, 6)); + assertFalse(searchMatrix(matrix, 10)); + assertFalse(searchMatrix(matrix, -1)); + } + + @Test + public void test2() { + int[][] matrix = new int[][]{ + {} + }; + assertFalse(searchMatrix(matrix, 10)); + } + + /** + * Better version + * @param matrix + * @param target + * @return + */ + public boolean searchMatrixBetter(int[][] matrix, int target) { + if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false; + + // start from bottom left corner + // if less than current, do row-- + // if greater, then col++ + + int row = matrix.length - 1; + int col = 0; + while (row >=0 && col < matrix[0].length) { + if (matrix[row][col] == target) return true; + + if (matrix[row][col] > target) { + row--; + } else { + col++; + } + } + return false; + } + + @Test + public void test3() { + int[][] matrix = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8,9}}; + assertTrue(searchMatrixBetter(matrix, 3)); + assertTrue(searchMatrixBetter(matrix, 6)); + assertFalse(searchMatrixBetter(matrix, 10)); + assertFalse(searchMatrixBetter(matrix, -1)); + } + + @Test + public void test4() { + int[][] matrix = new int[][]{ + {} + }; + assertFalse(searchMatrixBetter(matrix, 10)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SearchRotatedArray.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SearchRotatedArray.java new file mode 100644 index 0000000..9db46f8 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SearchRotatedArray.java @@ -0,0 +1,67 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. + *

+ * (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]).s + *

+ * Input: nums = [4,5,6,7,0,1,2], target = 0 + * Output: 4 + *

+ *

+ * https://leetcode.com/problems/search-in-rotated-sorted-array/ + */ +public class SearchRotatedArray { + public int search(int[] nums, int target) { + int start = 0; + int end = nums.length - 1; + + while (start <= end) { + int mid = start + (end - start) / 2; + if (nums[mid] == target) return mid; + + // if left part is sorted + if (nums[start] <= nums[mid]) { + // make sure target falls in sorted part + if (nums[start] <= target && target < nums[mid]) { + end = mid - 1; + } else { + start = mid + 1; + } + } else { + + if (nums[mid] < target && target <= nums[end]) { + start = mid + 1; + } else { + end = mid - 1; + } + } + } + return -1; + } + + @Test + public void test1() { + assertEquals(0, search(new int[]{4, 5, 6, 7, 0, 1, 2}, 4)); + assertEquals(1, search(new int[]{4, 5, 6, 7, 0, 1, 2}, 5)); + assertEquals(2, search(new int[]{4, 5, 6, 7, 0, 1, 2}, 6)); + assertEquals(3, search(new int[]{4, 5, 6, 7, 0, 1, 2}, 7)); + assertEquals(4, search(new int[]{4, 5, 6, 7, 0, 1, 2}, 0)); + assertEquals(5, search(new int[]{4, 5, 6, 7, 0, 1, 2}, 1)); + assertEquals(6, search(new int[]{4, 5, 6, 7, 0, 1, 2}, 2)); + } + + @Test + public void test2() { + assertEquals(4, search(new int[]{4, 5, 6, 7, 8, 1, 2, 3}, 8)); + } + + @Test + public void test3() { + assertEquals(1, search(new int[]{3, 1}, 1)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SentenceSimilarityII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SentenceSimilarityII.java new file mode 100644 index 0000000..fdb6e65 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SentenceSimilarityII.java @@ -0,0 +1,68 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static java.util.Arrays.asList; +import static org.junit.Assert.assertTrue; + +/** + * https://leetcode.com/problems/sentence-similarity-ii/ + */ +public class SentenceSimilarityII { + + // Time O(N * logP) + public boolean areSentencesSimilarTwo(String[] words1, String[] words2, List> pairs) { + + if (words1 == null || words2 == null || words1.length != words2.length) return false; + + Map parents = new HashMap<>(); + + int n = words1.length; + + for (List pair : pairs) { + String u = pair.get(0); + String v = pair.get(1); + + if (!parents.containsKey(u)) parents.put(u, u); + if (!parents.containsKey(v)) parents.put(v, v); + + if (!find(parents, u).equals(find(parents, v))) { + union(parents, u, v); + } + } + + for (int i = 0; i < n; i++) { + String u = words1[i]; + String v = words2[i]; + + if (u.equals(v)) continue; + + if (!parents.containsKey(u) || !parents.containsKey(v) || !find(parents, u).equals(find(parents, v))) { + return false; + } + } + + return true; + } + + private String find(Map parents, String u) { + while (!u.equals(parents.get(u))) { + u = parents.get(u); + } + return u; + } + + private void union(Map parents, String u, String v) { + parents.put(find(parents, v), find(parents, u)); + } + + @Test + public void test() { + assertTrue(areSentencesSimilarTwo(new String[]{"great", "acting", "skills"}, new String[]{"fine", "drama", "talent"}, + asList(asList("great", "good"), asList("fine", "good"), asList("drama", "acting"), asList("skills", "talent")))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ShortestPalindromeSubstring.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ShortestPalindromeSubstring.java new file mode 100644 index 0000000..647edb7 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ShortestPalindromeSubstring.java @@ -0,0 +1,110 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/shortest-palindrome/ + * + * Given a string s, you are allowed to convert it to a palindrome by adding characters in front of it. + * Find and return the shortest palindrome you can find by performing this transformation. + * + * Example 1: + * + * Input: "aacecaaa" + * Output: "aaacecaaa" + * Example 2: + * + * Input: "abcd" + * Output: "dcbabcd" + */ +public class ShortestPalindromeSubstring { + public String shortestPalindrome(String s) { + if (s.length() <= 1) return s; + // find longest palindrome p substring in s + // if indexof(p) == 0 + // app chars from p.length() .. s.length() + // else add chars from 1 .. s.length() + + int longest = longestPalindromeSubstringKmp(s); + if (longest == s.length()) return s; + + StringBuilder sb = new StringBuilder(); + sb.append(s.substring(longest)); + + return sb.reverse().toString() + s; + } + + private int longestPalindromeSubstringKmp(String s) { + int[] lps = findLps(s + "#" + new StringBuilder(s).reverse().toString()); + return lps[lps.length - 1]; + } + + private int[] findLps(String s) { + int[] lps = new int[s.length()]; + + lps[0] = 0; + int j = 0; + int i = 1; + + while (i < s.length()) { + if (s.charAt(i) == s.charAt(j)) { + j++; + lps[i] = j; + i++; + } else { + if (j != 0) { + j = lps[j - 1]; + } else { + lps[i] = 0; + i++; + } + } + } + return lps; + } + + + /** + * Time O(n^2) + * Space O(1) + * + * @param s + * @return + */ + private String longestPalindromeSubstring(String s) { + int n = s.length(); + + int start = 0; + int end = n - 1; + + int palindrome = end; + + while (start < end) { + if (s.charAt(start) == s.charAt(end)) { + start++; + end--; + } else { + start = 0; + end = palindrome - 1; + palindrome = end; + } + + } + + return s.substring(0, palindrome + 1); + } + + @Test + public void test() { + assertEquals("ababbabbbababbbabbaba", shortestPalindrome("ababbbabbaba")); + assertEquals("aba", shortestPalindrome("aba")); + assertEquals("dcbabcd", shortestPalindrome("abcd")); + assertEquals("aaacecaaa", shortestPalindrome("aacecaaa")); + assertEquals("bbabb", shortestPalindrome("abb")); + assertEquals("abbaabba", shortestPalindrome("aabba")); + assertEquals("abbbaaaabbba", shortestPalindrome("aaaabbba")); + assertEquals("abbbaaaaabbba", shortestPalindrome("aaaaabbba")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ShortestUnsortedConArr.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ShortestUnsortedConArr.java new file mode 100644 index 0000000..20f299b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ShortestUnsortedConArr.java @@ -0,0 +1,101 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + +/** + * Given an integer array, you need to find one continuous subarray that if you only sort this subarray in ascending order, then the whole array will be sorted in ascending order, too. + * + * You need to find the shortest such subarray and output its length. + * + * Example 1: + * Input: [2, 6, 4, 8, 10, 9, 15] + * Output: 5 + * Explanation: You need to sort [6, 4, 8, 10, 9] in ascending order to make the whole array sorted in ascending order. + */ +public class ShortestUnsortedConArr { + /** + * O(nlogn) - Time + * O(n) - space + * @param nums + * @return + */ + public int findUnsortedSubarray(int[] nums) { + int[] temp = Arrays.copyOf(nums, nums.length); + Arrays.sort(temp); + + int start = -1; + int end = -1; + + for (int i = 0; i < nums.length; i++) { + if (nums[i] != temp[i]) { + if (start == -1) { + start = i; + } + end = i; + } + } + if (start == -1) return 0; + + return (end - start) + 1; + } + + @Test + public void testFindUnsortedSubArray() { + assertEquals(5, findUnsortedSubarray(new int[] {2, 6, 4, 8, 10, 9, 15})); + assertEquals(0, findUnsortedSubarray(new int[] {1, 2, 4, 8, 10, 15})); + assertEquals(0, findUnsortedSubarray(new int[] {1, 2, 2, 8, 10, 15})); + assertEquals(4, findUnsortedSubarray(new int[] {1, 3, 2, 3, 2, 15})); + assertEquals(2, findUnsortedSubarray(new int[] {1, 3, 2, 3, 3, 15})); + assertEquals(4, findUnsortedSubarray(new int[] {1, 3, 2, 2, 2})); + assertEquals(3, findUnsortedSubarray(new int[] {2, 3, 3, 2, 4})); + assertEquals(3, findUnsortedSubarray(new int[] {1, 2, 4, 5, 3})); + } + + /** + * O(n) - Time + * O(1) - space + * + * @param nums + * @return + */ + public int findUnsortedSubarrayBetter(int[] nums) { + int len = nums.length - 1; + int start = -1; + int end = -2; + + int max = nums[0]; + int min = nums[len]; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] < max) { + end = i; + } else if (nums[i] > max) { + max = nums[i]; + } + + if (nums[len - i] > min) { + start = len - i; + } else if (nums[len - i] < min) { + min = nums[len - i]; + } + } + + return (end - start) + 1; + } + + @Test + public void testFindUnsortedSubArrayBetter() { + assertEquals(5, findUnsortedSubarrayBetter(new int[] {2, 6, 4, 8, 10, 9, 15})); + assertEquals(0, findUnsortedSubarrayBetter(new int[] {1, 2, 4, 8, 10, 15})); + assertEquals(0, findUnsortedSubarrayBetter(new int[] {1, 2, 2, 8, 10, 15})); + assertEquals(4, findUnsortedSubarrayBetter(new int[] {1, 3, 2, 3, 2, 15})); + assertEquals(2, findUnsortedSubarrayBetter(new int[] {1, 3, 2, 3, 3, 15})); + assertEquals(4, findUnsortedSubarrayBetter(new int[] {1, 3, 2, 2, 2})); + assertEquals(3, findUnsortedSubarrayBetter(new int[] {2, 3, 3, 2, 4})); + assertEquals(3, findUnsortedSubarrayBetter(new int[] {1, 2, 4, 5, 3})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SingleElementInSortedArray.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SingleElementInSortedArray.java new file mode 100644 index 0000000..fd7b222 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SingleElementInSortedArray.java @@ -0,0 +1,66 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/single-element-in-a-sorted-array/ + */ +public class SingleElementInSortedArray { + public int singleNonDuplicate(int[] nums) { + int n = nums.length; + + int lo = 0; + int hi = n - 1; + + while (lo <= hi) { + int mid = lo + (hi - lo) / 2; + + // 1,2,2 + int left = mid - lo + 1; // 2 + + if (mid > 0 && nums[mid - 1] == nums[mid]) { + left = mid - lo + 1; + } else if (mid < n - 1 && nums[mid + 1] == nums[mid]) { + left = mid - lo; + } else { + return nums[mid]; + } + + if (left % 2 == 0) { + // look into right + if (mid > 0 && nums[mid - 1] == nums[mid]) { + lo = mid + 1; + } else { + lo = mid; + } + + } else { + // look into left + if (mid > 0 && nums[mid - 1] == nums[mid]) { + hi = mid + 1; + } else if (mid + 1 < n && nums[mid + 1] == nums[mid]) { + hi = mid - 1; + } else { + hi = mid; + } + } + + // now we need to go the section where length is odd + } + + return -1; + } + + @Test + public void test() { + assertEquals(1, singleNonDuplicate(new int[] {1,2,2})); + assertEquals(2, singleNonDuplicate(new int[] {1,1,2})); + assertEquals(2, singleNonDuplicate(new int[] {1,1,2,3,3,4,4,8,8})); + assertEquals(1, singleNonDuplicate(new int[] {1,2,2,3,3,4,4,8,8})); + assertEquals(3, singleNonDuplicate(new int[] {1,1,2,2,3,4,4,8,8})); + assertEquals(4, singleNonDuplicate(new int[] {1,1,2,2,3,3,4,8,8})); + assertEquals(8, singleNonDuplicate(new int[] {1,1,2,2,3,3,4,4,8})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SkylineProblem.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SkylineProblem.java new file mode 100644 index 0000000..7e5973b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SkylineProblem.java @@ -0,0 +1,111 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.TreeMap; + +import static com.google.common.collect.Lists.newArrayList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/the-skyline-problem/ + */ +public class SkylineProblem { + public List> getSkyline(int[][] buildings) { + List> l = new ArrayList<>(); + + int n = buildings.length; + + if (n == 0) return l; + + // we'll create points with x-value and height and mark if it is start + // or end for that particular building + int[][] points = new int[2 * n][3]; + + for (int i = 0, j = 0; i < n; i++, j += 2) { + int start = buildings[i][0]; + int end = buildings[i][1]; + int height = buildings[i][2]; + + points[j] = new int[]{start, height, 0}; // points[2] == 0 -> start + points[j + 1] = new int[]{end, height, 1}; // points[2] == 1 -> end + } + + // now sort points with start + // if start are equals, then sort them with height or start/end to cover corner cases + Arrays.sort(points, (p1, p2) -> { + int diff = p1[0] - p2[0]; + + if (diff == 0) { + // if both are start point, then we process taller building + if (p1[2] == 0 && p2[2] == 0) { + return p2[1] - p1[1]; + } else if (p1[2] == 1 && p2[2] == 1) { // if both are end point, then we process shorter building first + return p1[1] - p2[1]; + } else { + return p1[2] - p2[0]; // if start of one is end of other, then start has to be processed first + } + } + return diff; + }); + + /** + * 1. have priority queue starting with element 0 + * and max = 0 + * 2. for each point, if it is + * a) start, then put height h into pq, if it changes max, then add (start, h) into result list + * b) end, then remove height h from pq, if it changes max, then add (end, max) int result list + * + * + * Since PriorityQueue has remove with time O(n), overall Time O(n^2) + * But, TreeMap has O(logn) for remove as well. So, we'll use TreeMap + */ + + TreeMap pq = new TreeMap<>((i1, i2) -> i2 - i1); + pq.put(0, 1); + int max = 0; + + for (int[] point : points) { + if (point[2] == 0) { // start + int height = point[1]; + pq.put(height, pq.getOrDefault(height, 0) + 1); + + if (max == pq.firstKey()) continue; + + max = pq.firstKey(); + l.add(newArrayList(point[0], height)); + } else { // end + int rem = pq.get(point[1]) - 1; + if (rem == 0) { + pq.remove(point[1]); + } else { + pq.put(point[1], rem); + } + + if (max == pq.firstKey()) continue; + + max = pq.firstKey(); + + l.add(newArrayList(point[0], max)); + } + } + + return l; + } + + @Test + public void test() { + int[][] buildings = {{2, 9, 10}, {3, 7, 15}, {5, 12, 12}, {15, 20, 10}, {19, 24, 8}}; + List> points = getSkyline(buildings); + + List> expected = newArrayList(newArrayList(2, 10), newArrayList(3, 15), + newArrayList(7, 12), newArrayList(12, 0), newArrayList(15, 10), + newArrayList(20, 8), newArrayList(24, 0)); + + assertThat(points, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SmallestRangeKList.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SmallestRangeKList.java new file mode 100644 index 0000000..e308e04 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SmallestRangeKList.java @@ -0,0 +1,55 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.List; +import java.util.PriorityQueue; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/smallest-range-covering-elements-from-k-lists/ + */ +public class SmallestRangeKList { + public int[] smallestRange(List> nums) { + int n = nums.size(); + + if (n == 0) return new int[0]; + + int x = 0, y = Integer.MAX_VALUE; + int max = Integer.MIN_VALUE; + PriorityQueue pq = new PriorityQueue<>((i1, i2) -> i1[2] - i2[2]); + + for (int i = 0; i < n; i++) { + List l = nums.get(i); + max = Math.max(l.get(0), max); + pq.offer(new int[] {i, 0, l.get(0)}); + } + + while (pq.size() == n) { + int[] curr = pq.poll(); + + int r = curr[0]; + int c = curr[1]; + + if (y - x > max - curr[2]) { + x = nums.get(r).get(c); + y = max; + } + + if (c + 1 < nums.get(r).size()) { + pq.offer(new int[] {r, c + 1, nums.get(r).get(c + 1)}); + max = Math.max(max, nums.get(r).get(c + 1)); + } + } + + return new int[] {x, y}; + } + + @Test + public void test() { + assertThat(smallestRange(asList(asList(4,10,15,24,26), asList(0,9,12,20), asList(5,18,22,30))), is(new int[] {20,24})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SpiralMatrix.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SpiralMatrix.java new file mode 100644 index 0000000..da7ae30 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SpiralMatrix.java @@ -0,0 +1,76 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * Given a matrix of order m x n, return spiral traversal of the matrix. + */ +public class SpiralMatrix { + public List spiralOrder(int[][] matrix) { + + List l = new ArrayList<>(); + + + if (matrix == null) return l; + + int rowStart = 0; + int rowEnd = matrix.length - 1; + int colStart = 0; + int colEnd = matrix[0].length - 1; + + + boolean[][] visited = new boolean[matrix.length][matrix[0].length]; + + while (rowStart <= rowEnd && colStart <= colEnd) { + for (int i = colStart; i <= colEnd && !visited[rowStart][i]; i++) { + l.add(matrix[rowStart][i]); + visited[rowStart][i] = true; + } + + rowStart++; + for (int i = rowStart; i <= rowEnd && !visited[i][colEnd]; i++) { + l.add(matrix[i][colEnd]); + visited[i][colEnd] = true; + } + colEnd--; + for (int i = colEnd; i >= colStart && !visited[rowEnd][i]; i--) { + l.add(matrix[rowEnd][i]); + visited[rowEnd][i] = true; + } + + rowEnd--; + for (int i = rowEnd; i >= rowStart && !visited[i][colStart]; i--) { + l.add(matrix[i][colStart]); + visited[i][colStart] = true; + } + colStart++; + } + + return l; + } + + @Test + public void test1() { + int[][] arr = new int[][]{{1, 2, 3}, {8, 9, 4}, {7, 6, 5}}; + List expected = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9); + assertThat(spiralOrder(arr), is(expected)); + } + + @Test + public void test2() { + int[][] arr = new int[][]{ + {1, 2, 3, 10}, + {8, 9, 4, 11}, + {7, 6, 5, 12} + }; + List expected = Arrays.asList(1, 2, 3, 10, 11, 12, 5, 6, 7, 8, 9, 4); + assertThat(spiralOrder(arr), is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SpiralMatrixII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SpiralMatrixII.java new file mode 100644 index 0000000..7344eb9 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SpiralMatrixII.java @@ -0,0 +1,50 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class SpiralMatrixII { + public int[][] generateMatrix(int n) { + int[][] m = new int[n][n]; + int val = 0; + for (int i = 0; i <= (n / 2); i++) { + int row = i; + int col = i; + // top + for (; col < n - i; col++) { + m[row][col] = ++val; + } + + col--; + row++; + // right + for (; row < n - i; row++) { + m[row][col] = ++val; + } + + // bottom + row--; + col--; + for (; col >= i; col--) { + m[row][col] = ++val; + } + + // left + row--; + col++; + for (; row > i; row--) { + m[row][col] = ++val; + } + } + return m; + } + + @Test + public void test() { + int[][] matrix = generateMatrix(3); + int[][] expected = new int[][]{{1, 2, 3}, {8, 9, 4}, {7, 6, 5}}; + assertThat(matrix, is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/StrStr.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/StrStr.java new file mode 100644 index 0000000..f7cb76c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/StrStr.java @@ -0,0 +1,46 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/implement-strstr/ + */ +public class StrStr { + public int strStr(String haystack, String needle) { + if (haystack == null + || needle == null || needle.length() == 0) return 0; + + // pre-processing of needle + char[] s = new char[256]; + for (char ch : needle.toCharArray()) { + s[ch]++; + } + + int h = haystack.length(); + int n = needle.length(); + for (int i = 0; i + n < h; ) { + if (s[haystack.charAt(n - 1 + i)] > 0) { // haystack matches character, so look within + boolean matches = true; + int iEnd = n - 1 + i; + for (int j = n - 1; j >= 0; j--, iEnd--) { + if (needle.charAt(j) != haystack.charAt(iEnd)) { + matches = false; + break; + } + } + if (matches) return i; + i++; + } else { + i += n; + } + } + return -1; + } + + @Test + public void test1() { + assertEquals(2, strStr("hello", "ll")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SuperUglyNumber.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SuperUglyNumber.java new file mode 100644 index 0000000..da798f1 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/SuperUglyNumber.java @@ -0,0 +1,54 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.PriorityQueue; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * Write a program to find the nth super ugly number. + * + * Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k. + * + * Example: + * + * Input: n = 12, primes = [2,7,13,19] + * Output: 32 + * Explanation: [1,2,4,7,8,13,14,16,19,26,28,32] is the sequence of the first 12 + * super ugly numbers given primes = [2,7,13,19] of size 4. + */ +public class SuperUglyNumber { + public int nthSuperUglyNumber(int n, int[] primes) { + PriorityQueue q = new PriorityQueue<>(); + for (int prime: primes) { + q.add((long) prime); + } + if (primes.length == 1) { + return (int) Math.pow(primes[0], n - 1); + } + int count = 1; + long ugly = 1; + while (count < n) { + ugly = q.poll(); + + if (ugly != q.peek()) { + count++; + for (int prime: primes) { + long potentialUgly = prime * ugly; + q.add(potentialUgly); + } + } + + } + return (int) ugly; + } + + @Test + public void test() { + assertEquals(32, nthSuperUglyNumber(12, new int[] {2, 7, 13, 19})); + assertEquals(2, nthSuperUglyNumber(2, new int[] {2})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TargetSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TargetSum.java new file mode 100644 index 0000000..5d05cc5 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TargetSum.java @@ -0,0 +1,67 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/target-sum/ + */ +public class TargetSum { + /*public int findTargetSumWays(int[] nums, int S) { + int[] dp = new int[S + 1]; + for (int n: nums) { + if (n < S) { + dp[n] = 1; + } + } + for (int i = 1; i <= S; i++) { + for (int n: nums) { + if (i >= n) + dp[i] += dp[i - n]; + +// if (i + n <= S) +// dp[i] += dp[i + n]; + } + } + + return dp[S - 1]; + }*/ + + public int findTargetSumWays(int[] nums, int S) { + Map mem = new HashMap<>(); + + return dfs(nums, S, 0, mem); + } + + private int dfs(int[] nums, int target, int idx, Map mem) { // 3, 0, 0 + + if (idx > nums.length) return 0; + + if (nums.length == idx) { + if (target == 0) + return 1; // target = 3, sum = -4, idx = 4 + return 0; + } + + String key = target + "#" + idx; + + if (mem.containsKey(key)) return mem.get(key); + + int curr = dfs(nums, target - nums[idx], idx + 1, mem) + + dfs(nums, target + nums[idx], idx + 1, mem); + + mem.put(key, curr); + + return mem.get(key); + } + + + @Test + public void test1() { // 9725438598 + assertEquals(5, findTargetSumWays(new int[] {1, 1, 1, 1, 1}, 3)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TaskScheduler.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TaskScheduler.java new file mode 100644 index 0000000..499e360 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TaskScheduler.java @@ -0,0 +1,69 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/task-scheduler/ + */ +public class TaskScheduler { + /** + * 1. count tasks + * 2. put tasks into priority queue + * 3. fill distances arr with -1 (noting -1 is unreachable) + * 4. pull the from pq with highest count (as we want to finish those task first) + * 5. if polled task is not in enough interval n, then keep looking another + * ready task + * 6. update the interval for each task + * + * @param tasks + * @param n + * @return + */ + public int leastInterval(char[] tasks, int n) { + int[] counts = new int[26]; + for (char task: tasks) { + counts[task - 'A']++; + } + + PriorityQueue pq = new PriorityQueue<>((a1, a2) -> a2 - a1); + for (int count: counts) { + if (count > 0) + pq.add(count); + } + + + int count = 0; + + while (!pq.isEmpty()) { + + List temp = new ArrayList<>(); + + for (int i = 0; i <= n; i++) { + if (!pq.isEmpty()) { + int next = pq.poll(); + if (next > 1) { + temp.add(next - 1); + } + } + + count++; + + if (pq.isEmpty() && temp.isEmpty()) break; + } + + for (int rem: temp) pq.offer(rem); + } + + return count; + } + + @Test + public void test() { + assertEquals(8, leastInterval(new char[] {'A','A','A','B','B','B'}, 2)); + assertEquals(16, leastInterval(new char[] {'A','A','A','A','A','A','B','C','D','E','F','G'}, 2)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TernaryExpression.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TernaryExpression.java new file mode 100644 index 0000000..62f43d0 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TernaryExpression.java @@ -0,0 +1,46 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/ternary-expression-parser/ + */ +public class TernaryExpression { + public String parseTernary(String expression) { + int n = expression.length(); + if (n <= 1) return expression; + + char first = expression.charAt(0); + + int i = 1; + int ques = 0; + + while (i < n) { + if (expression.charAt(i) == ':') { + ques--; + if (ques == 0) break; + } else if (expression.charAt(i) == '?') ques++; + + i++; + } + + if (first == 'T') { + // take first part + + return parseTernary(expression.substring(2, i)); + } else { + // take second part + return parseTernary(expression.substring(i + 1)); + } + + } + + @Test + public void test() { + assertEquals("2", parseTernary("T?2:3")); + assertEquals("4", parseTernary("F?1:T?4:5")); + assertEquals("F", parseTernary("T?T?F:5:3")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TrappingRainWater.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TrappingRainWater.java new file mode 100644 index 0000000..d47b3f4 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TrappingRainWater.java @@ -0,0 +1,39 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/trapping-rain-water/ + */ +public class TrappingRainWater { + public int trap(int[] height) { + if (height.length == 0) return 0; + + int n = height.length; + int[] lMax = new int[n]; + lMax[0] = height[0]; + + for (int i = 1; i < n; i++) { + lMax[i] = Math.max(height[i], lMax[i - 1]); + } + + int[] rMax = new int[n]; + rMax[n - 1] = height[n - 1]; + for (int i = n - 2; i >= 0; i--) { + rMax[i] = Math.max(rMax[i + 1], height[i]); + } + + int vol = 0; + for (int i = 0; i < n; i++) { + vol += Math.min(lMax[i], rMax[i]) - height[i]; + } + return vol; + } + + @Test + public void test() { + assertEquals(6, trap(new int[] {0,1,0,2,1,0,1,3,2,1,2,1})); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TwoCitySchedule.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TwoCitySchedule.java new file mode 100644 index 0000000..ec18fde --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/TwoCitySchedule.java @@ -0,0 +1,67 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/two-city-scheduling/submissions/ + */ +public class TwoCitySchedule { + public int twoCitySchedCost(int[][] costs) { + int costA = 0; + int costB = 0; + + // sort entries so that we can look greedily the mini first for both city A and B + Arrays.sort(costs, (c1, c2) -> (Math.abs(c2[0] - c2[1]) - Math.abs(c1[0] - c1[1]))); + + int countA = 0; + int countB = 0; + for (int[] cost : costs) { + if (countB == costs.length / 2) { + costA += cost[0]; + countA++; + } else if (countA == costs.length / 2) { + costB += cost[1]; + countB++; + } else { + + if (cost[0] <= cost[1]) { + costA += cost[0]; + countA++; + } else { + costB += cost[1]; + countB++; + } + + } + } + return costA + costB; + } + + @Test + public void test1() { + int[][] costs = new int[][]{ + {100, 20}, {30, 20}, {400, 50}, {30, 30} + }; + assertEquals(130, twoCitySchedCost(costs)); + } + + @Test + public void test2() { + int[][] costs = new int[][]{ + {259, 770}, {448, 54}, {926, 667}, {184, 139}, {840, 118}, {577, 469} + }; + assertEquals(1859, twoCitySchedCost(costs)); + } + + @Test + public void test3() { + int[][] costs = new int[][]{ + {515, 563}, {451, 713}, {537, 709}, {343, 819}, {855, 779}, {457, 60}, {650, 359}, {631, 42} + }; + assertEquals(3086, twoCitySchedCost(costs)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ValidPalindromeII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ValidPalindromeII.java new file mode 100644 index 0000000..53e3226 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ValidPalindromeII.java @@ -0,0 +1,47 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +/** + * Find if you can make a string palindrome by removing atmost one character + * + * https://leetcode.com/problems/valid-palindrome-ii/ + */ +public class ValidPalindromeII { + + public boolean validPalindrome(String s) { + if (s == null || s.isEmpty() || s.length() == 1) return true; + int start = 0; + int end = s.length() - 1; + while (start <= end) { + if (s.charAt(start) != s.charAt(end)) { + + return validPalindrome(s, start + 1, end) + || validPalindrome(s, start, end - 1); + } + start++; + end--; + } + return true; + } + + private boolean validPalindrome(String s, int start, int end) { + if (s.isEmpty()) return true; + while (start <= end) { + if (s.charAt(start) != s.charAt(end)) return false; + start++; + end--; + } + return true; + } + + @Test + public void test1() { + assertTrue(validPalindrome("abda")); + assertFalse(validPalindrome("abbcda")); + assertTrue(validPalindrome("aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ValidSudoku.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ValidSudoku.java new file mode 100644 index 0000000..0d479d4 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/ValidSudoku.java @@ -0,0 +1,84 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static junit.framework.TestCase.*; + +/** + * https://leetcode.com/explore/featured/card/top-interview-questions-easy/92/array/769/ + * + * Determine if the filled suduko is valid + */ +public class ValidSudoku { + public boolean isValidSudoku(char[][] board) { + // valid row and col + // row++, col++ + for (int r = 0; r < board.length; r++) { + for (int c = 0; c < board[0].length; c++) { + if (board[r][c] != '.' && !valid(board, r, c)) { + return false; + } + } + } + return true; + } + + private boolean valid(char[][] board, int r, int c) { + // valid row + for (int col = 0; col < 9; col++) { + if (c != col && board[r][col] == board[r][c]) return false; + } + + // valid col + for (int row = 0; row < 9; row++) { + if (r != row && board[row][c] == board[r][c]) return false; + } + + int rStart = r / 3 * 3; + int cStart = c / 3 * 3; + + for (int i = 0; i < 3; i++) { + for (int j = 0; j < 3; j++) { + if ((i + rStart) != r && (j + cStart) != c + && board[i + rStart][j + cStart] == board[r][c]) { + return false; + } + } + } + + return true; + } + + @Test + public void test1() { + char[][] board = new char[][]{ + {'8', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + + }; + assertFalse(isValidSudoku(board)); + } + + @Test + public void test2() { + char[][] board = new char[][]{ + {'5', '3', '.', '.', '7', '.', '.', '.', '.'}, + {'6', '.', '.', '1', '9', '5', '.', '.', '.'}, + {'.', '9', '8', '.', '.', '.', '.', '6', '.'}, + {'8', '.', '.', '.', '6', '.', '.', '.', '3'}, + {'4', '.', '.', '8', '.', '3', '.', '.', '1'}, + {'7', '.', '.', '.', '2', '.', '.', '.', '6'}, + {'.', '6', '.', '.', '.', '.', '2', '8', '.'}, + {'.', '.', '.', '4', '1', '9', '.', '.', '5'}, + {'.', '.', '.', '.', '8', '.', '.', '7', '9'} + }; + assertTrue(isValidSudoku(board)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/VerifyPreorder.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/VerifyPreorder.java new file mode 100644 index 0000000..ea89b32 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/VerifyPreorder.java @@ -0,0 +1,51 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * with given pre-order traversal, verify if the tree is valid or not + */ +public class VerifyPreorder { + public boolean isValidSerialization(String preorder) { + // stack 9 2 3 1 4 + // replace node having two # with # + Stack stack = new Stack<>(); + String[] parts = preorder.split(","); + for (int i = 0; i < parts.length; i++) { + stack.push(parts[i]); + if ("#".equals(stack.peek())) { + int popCount = 0; + while (stack.peek().equals("#")) { + stack.pop(); + if (stack.isEmpty()) break; + popCount++; + + if (popCount == 2) { + stack.pop(); // pop parent node + stack.push("#"); + popCount = 0; + } + + + } + if (i < parts.length - 1 && stack.isEmpty()) return false; + + stack.push("#"); + } + } + + return stack.size() == 1 && "#".equals(stack.peek()); + } + + @Test + public void test() { + assertTrue(isValidSerialization("9,3,4,#,#,1,#,#,2,#,6,#,#")); + assertFalse(isValidSerialization("1,#")); + assertFalse(isValidSerialization("9,#,#,1")); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WiggleSortII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WiggleSortII.java new file mode 100644 index 0000000..a3277d8 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WiggleSortII.java @@ -0,0 +1,97 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import static org.junit.Assert.assertArrayEquals; + +/** + * https://leetcode.com/problems/wiggle-sort-ii/ + * + * nums[0] < nums[1] > nums[2] < nums[3] ... + */ +public class WiggleSortII { + + public void wiggleSort(int[] nums) { + int n = nums.length; + + sort(nums, 0, n - 1); + + int l = 0; + int r = n - 1; + + int mid = l + (r - l) / 2; + + int[] temp = new int[n]; + + int p1 = mid, p2 = n - 1; + + int i = 0; + + while (p1 >= 0 || p2 > mid) { + if (i % 2 == 0) { + temp[i++] = nums[p1--]; + } else { + temp[i++] = nums[p2--]; + } + } + + for (i = 0; i < n; i++) { + nums[i] = temp[i]; + } + } + + private void sort(int[] nums, int l, int r) { + if (l < r) { + int mid = l + (r - l) / 2; + int p = partition(nums, l, r, mid); + sort(nums, l, p - 1); + sort(nums, p + 1, r); + } + } + + private int partition(int[] nums, int l, int r, int p) { + int pivot = nums[p]; + int i = l; + + swap(nums, p, r); + + for (int j = l; j < r; j++) { + if (nums[j] < pivot) { + swap(nums, i, j); + i++; + } + } + + swap(nums, i, r); + return i; + } + + private void swap(int[] nums, int i, int j) { + int temp = nums[j]; + nums[j] = nums[i]; + nums[i] = temp; + } + + @Test + public void test1() { + int[] expected = {2, 3, 1, 3, 1, 2}; + int[] actual = {1, 3, 2, 2, 3, 1}; + wiggleSort(actual); + assertArrayEquals(expected, actual); + } + + @Test + public void test2() { + int[] expected = {1, 6, 1, 5, 1, 4}; // 1 1 1 6 5 4 + int[] actual = {1, 1, 1, 5, 6, 4}; + wiggleSort(actual); + assertArrayEquals(expected, actual); + } + + @Test + public void test3() { + int[] actual = {5,3,1,2,6,7,8,5,5}; + wiggleSort(actual); + System.out.println(actual); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WordBreak.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WordBreak.java new file mode 100644 index 0000000..0279840 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WordBreak.java @@ -0,0 +1,116 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +/** + * Given a non-empty string s and a dictionary wordDict containing a list of non-empty words, determine + * if s can be segmented into a space-separated sequence of one or more dictionary words. + *

+ * Note: + *

+ * The same word in the dictionary may be reused multiple times in the segmentation. + * You may assume the dictionary does not contain duplicate words. + * Example 1: + *

+ * Input: s = "leetcode", wordDict = ["leet", "code"] + * Output: true + * Explanation: Return true because "leetcode" can be segmented as "leet code". + */ +public class WordBreak { + + Trie trie = new Trie(); + + public boolean wordBreak(String s, List wordDict) { + for (String word : wordDict) { + trie.insert(word); + } + Node root = trie.root; + + return wordBreak(s, root); + } + + private boolean wordBreak(String s, Node node) { + if ((s == null || s.isEmpty()) && node.terminates()) return true; + else if (s == null || s.isEmpty()) return false; + + Node child = node.getChild(s.charAt(0)); + if (child != null && child.terminates()) { + return wordBreak(s.substring(1), trie.root) || wordBreak(s.substring(1), child); + } else if (child != null) { + return wordBreak(s.substring(1), child); + } else { + return node.terminates() && wordBreak(s, trie.root); + } + } + + @Test + public void test1() { + assertTrue(wordBreak("leetcode", Arrays.asList("leet", "code"))); + } + + @Test + public void test2() { + assertTrue(wordBreak("leetscode", Arrays.asList("leet", "leets", "code"))); + } + + @Test + public void test3() { + assertFalse(wordBreak("leetcode", Arrays.asList("leets", "code"))); + } + + @Test + public void test4() { + assertTrue(wordBreak("bb", Arrays.asList("a", "b", "bbb", "bbbbb"))); + } +} + +class Trie { + Node root = new Node('#'); + + void insert(String word) { + root.insert(word); + } +} + +class Node { + private char data; + Map children; + + Node(char data) { + this.data = data; + this.children = new HashMap<>(); + } + + void insert(String word) { + if (word != null && !word.isEmpty()) { + this.data = word.charAt(0); + Node child = children.get(this.data); + if (child == null) { + + child = new Node(this.data); + children.put(this.data, child); + + } + child.insert(word.substring(1)); + } else { + children.put('\0', null); + } + } + + + boolean terminates() { + return children.containsKey('\0'); + } + + Node getChild(char ch) { + return children.get(ch); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WordLadderII.java b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WordLadderII.java new file mode 100644 index 0000000..ca726fd --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/leetcode/WordLadderII.java @@ -0,0 +1,104 @@ +package com.eprogrammerz.examples.algorithm.leetcode; + +import org.junit.Test; + +import java.util.*; + +import static java.util.Arrays.asList; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + + +/** + * https://leetcode.com/problems/word-ladder-ii/ + */ +public class WordLadderII { + public List> findLadders(String beginWord, String endWord, List wordList) { + List> l = new ArrayList<>(); + if (!wordList.contains(endWord)) return l; + + Map> graph = new HashMap<>(); + + Set startSet = new HashSet<>(); + startSet.add(beginWord); + + Set dict = new HashSet<>(wordList); + + // to build the graph -> directed graph + bfs(startSet, endWord, graph, dict); + + + List temp = new ArrayList<>(); + temp.add(beginWord); + + // backtrack to create the result ladder + dfs(beginWord, endWord, l, graph, temp); + + return l; + } + + private void bfs(Set startSet, String endWord, Map> graph, Set dict) { + if (startSet.isEmpty()) return; // no more graph building + + Set temp = new HashSet<>(); + + boolean finish = false; + + dict.removeAll(startSet); + + for (String word : startSet) { + char[] chars = word.toCharArray(); + + for (int i = 0; i < chars.length; i++) { + char old = chars[i]; + + // change each char and see if we have a word in dict + for (char ch = 'a'; ch <= 'z'; ch++) { + chars[i] = ch; + + String next = new String(chars); + + if (dict.contains(next)) { + if (next.equals(endWord)) { + finish = true; + } else { + temp.add(next); + } + + graph.computeIfAbsent(word, s -> new ArrayList<>()).add(next); + } + + } + chars[i] = old; + } + } + + if (!finish) bfs(temp, endWord, graph, dict); + } + + private void dfs(String beginWord, String endWord, List> l, Map> graph, List temp) { + if (endWord.equals(beginWord)) { + l.add(new ArrayList<>(temp)); + + return; + } + + if (graph.containsKey(beginWord)) { + for (String word : graph.get(beginWord)) { + + temp.add(word); + dfs(word, endWord, l, graph, temp); + temp.remove(temp.size() - 1); + } + } + } + + @Test + public void test() { + assertThat(findLadders("hot", "dog", Arrays.asList("hot", "dog")), is(Collections.emptyList())); + + assertThat(findLadders("hit", "cog", Arrays.asList("hot","dot","dog","lot","log","cog")), + is(asList(asList("hit","hot","dot","dog","cog"), asList("hit","hot","lot","log","cog")))); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/BinaryTreeTilt.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/BinaryTreeTilt.java new file mode 100644 index 0000000..3cf1502 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/BinaryTreeTilt.java @@ -0,0 +1,78 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + +/** + * Given a binary tree, return the tilt of the whole tree. + * + * The tilt of a tree node is defined as the absolute difference between the sum of all left subtree node values and the sum of all right subtree node values. Null node has tilt 0. + * + * The tilt of the whole tree is defined as the sum of all nodes' tilt. + * + * Example: + * Input: + * 1 + * / \ + * 2 3 + * Output: 1 + * Explanation: + * Tilt of node 2 : 0 + * Tilt of node 3 : 0 + * Tilt of node 1 : |2-3| = 1 + * Tilt of binary tree : 0 + 0 + 1 = 1 + */ +public class BinaryTreeTilt { + private Map nodeSum = new HashMap<>(); + public int findTilt(TreeNode root) { + if (root == null) return 0; + int leftSum = findSum(root.left); + int rightSum = findSum(root.right); + + int rootTilt = Math.abs(leftSum - rightSum); + return rootTilt + findTilt(root.left) + findTilt(root.right); + } + + private int findSum(TreeNode root) { + if (root == null) return 0; + int sum = 0; + if (nodeSum.containsKey(root)) { + sum = nodeSum.get(root); + } else { + sum = root.val + findSum(root.left) + findSum(root.right); + nodeSum.put(root, sum); + } + + return sum; + } + + /** + * 6 + * / \ + * 3 7 + * / \ \ + * 2 5 1 + * \ + * 10 + *

+ * 6 -> 3 -> 2 -> 5 -> 7 -> 1 -> 10 + */ + @Test + public void test1() { + TreeNode root = new TreeNode(6); + root.left = new TreeNode(3); + root.right = new TreeNode(7); + + root.right.right = new TreeNode(1); + + root.left.left = new TreeNode(2); + root.left.right = new TreeNode(5); + root.right.right.right = new TreeNode(10); + + assertEquals(32, findTilt(root)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/ConstructBinaryTreeFromString.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/ConstructBinaryTreeFromString.java new file mode 100644 index 0000000..425a894 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/ConstructBinaryTreeFromString.java @@ -0,0 +1,57 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/construct-binary-tree-from-string/ + */ +public class ConstructBinaryTreeFromString { + public TreeNode str2tree(String s) { + if (s.length() == 0) return null; + + int i = 0; + int val = 0; + while (i < s.length()) { + if (s.charAt(i) == '(') break; + val = val * 10 + (s.charAt(i) - '0'); + i++; + } + + TreeNode root = new TreeNode(val); + + if (i == s.length()) return root; + + int open = 1; + + int start = ++i; + + while (i < s.length()) { + char ch = s.charAt(i); + if (ch == '(') open++; + else if (ch == ')') { + open--; + if (open == 0) { + break; + } + } + i++; + } + + root.left = str2tree(s.substring(start, i)); + if (i + 1 < s.length()) { + root.right = str2tree(s.substring(i + 2, s.length() - 1)); + } + + return root; + } + + @Test + public void test() { + TreeNode root = str2tree("4(2(3)(1))(6(5))"); + assertEquals(4, root.val); + assertEquals(2, root.left.val); + assertEquals(6, root.right.val); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/DeleteNodesAndReturnForest.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/DeleteNodesAndReturnForest.java new file mode 100644 index 0000000..d6bcf30 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/DeleteNodesAndReturnForest.java @@ -0,0 +1,80 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +public class DeleteNodesAndReturnForest { + public List delNodes(TreeNode root, int[] to_delete) { + + List l = new ArrayList<>(); + if (root == null) return l; + delNodes(root, to_delete, l); + return l; + } + + private void delNodes(TreeNode root, int[] toDelete, List l) { + if (root == null) return; + if (!isToDelete(toDelete, root.val)) { + l.add(root); + } + + Queue q = new LinkedList<>(); + q.add(root); + + while (!q.isEmpty()) { + TreeNode node = q.poll(); + if (isToDelete(toDelete, root.val)) { + delNodes(node.left, toDelete, l); + delNodes(node.right, toDelete, l); + } + else { + if (node.left != null) { + if (isToDelete(toDelete, node.left.val)) { + TreeNode temp = node.left; + node.left = null; + delNodes(temp.left, toDelete, l); + delNodes(temp.right, toDelete, l); + } else { + q.add(node.left); + } + + } + + if (node.right != null) { + if (isToDelete(toDelete, node.right.val)) { + TreeNode temp = node.right; + node.right = null; + delNodes(temp.left, toDelete, l); + delNodes(temp.right, toDelete, l); + } else { + q.add(node.right); + } + + } + } + + } + } + + private boolean isToDelete(int[] toDelete, int val) { + for (int n : toDelete) { + if (n == val) return true; + } + return false; + } + + @Test + public void test1() { + TreeNode n1 = new TreeNode(1); + n1.left = new TreeNode(2); + n1.right = new TreeNode(3); + n1.right.right = new TreeNode(4); + + List forest = delNodes(n1, new int[] {2,1}); + System.out.println(forest); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/FenwickTree.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/FenwickTree.java new file mode 100644 index 0000000..de99563 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/FenwickTree.java @@ -0,0 +1,74 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Representation to calculate prefix sum in O(logn) time + */ +public class FenwickTree { + /** + * Create binary indexed tree is basically updating it + * + * @param arr + * @return + */ + public int[] createBit(int[] arr) { + int n = arr.length; + int[] bit = new int[n + 1]; + + for (int i = 0; i < n; i++) { + updateBit(bit, i + 1, arr[i]); + } + + return bit; + } + + public void updateBit(int[] bit, int idx, int val) { + while (idx < bit.length) { + bit[idx] += val; + idx = nextIndex(idx); + } + } + + private int nextIndex(int idx) { + return idx + (idx & (-idx)); + } + + /** + * idx is index in input array + * We need to look until we reach end of parents of nodes + * + * @param idx + * @return + */ + public int prefixSum(int[] bit, int idx) { + // bit index is arr_index + 1 + idx = idx + 1; + int sum = 0; + while (idx > 0) { + sum += bit[idx]; + idx = parentIdx(idx); + } + return sum; + } + + private int parentIdx(int idx) { + return idx - (idx & (-idx)); + } + + @Test + public void test() { + int[] arr = new int[]{3, 2, -1, 6, 5, 4, -3}; + int[] bit = createBit(arr); + + assertEquals(3, prefixSum(bit, 0)); + assertEquals(5, prefixSum(bit, 1)); + assertEquals(4, prefixSum(bit, 2)); + assertEquals(10, prefixSum(bit, 3)); + assertEquals(15, prefixSum(bit, 4)); + assertEquals(19, prefixSum(bit, 5)); + assertEquals(16, prefixSum(bit, 6)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/FlattenBinaryTree.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/FlattenBinaryTree.java new file mode 100644 index 0000000..a55ffc2 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/FlattenBinaryTree.java @@ -0,0 +1,85 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import java.util.Stack; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +/** + * Given a binary tree, flatten it to a linked list in-place. + */ +public class FlattenBinaryTree { + /** + * Do dfs + * once updated stack with child nodes, update traverse node with current node as right node + * @param root + */ + public void flatten(TreeNode root) { + if (root == null) return; + + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + + if (node.right != null) { + stack.push(node.right); + } + + if (node.left != null) { + stack.push(node.left); + } + + if (node != root) { + root.right = node; + root.left = null; + root = root.right; + } + } + } + + + /** + * 6 + * / \ + * 3 7 + * / \ \ + * 2 5 1 + * \ + * 10 + *

+ * 6 -> 3 -> 2 -> 5 -> 7 -> 1 -> 10 + */ + + @Test + public void testPathSum() { + TreeNode root = new TreeNode(6); + root.left = new TreeNode(3); + root.right = new TreeNode(7); + + root.right.right = new TreeNode(1); + + root.left.left = new TreeNode(2); + root.left.right = new TreeNode(5); + root.right.right.right = new TreeNode(10); + + flatten(root); + + assertEquals(6, root.val); + + assertNull(root.left); + assertEquals(3, root.right.val); + + + assertNull(root.right.left); + assertEquals(2, root.right.right.val); + + assertNull(root.right.right.left); + assertEquals(5, root.right.right.right.val); + + assertNull(root.right.right.right.right.left); + assertEquals(7, root.right.right.right.right.val); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/IdenticalBinaryTree.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/IdenticalBinaryTree.java index c556505..0d39def 100644 --- a/src/main/java/com/eprogrammerz/examples/algorithm/trees/IdenticalBinaryTree.java +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/IdenticalBinaryTree.java @@ -75,7 +75,7 @@ public void testIsSameTree() { public int isSameTreeRecursive(TreeNode root1, TreeNode root2) { if (root1 == null && root2 == null) return 1; - if ((root1 != null && root2 == null) || (root1 == null && root2 != null)) return 0; + if (root1 == null || root2 == null) return 0; if (root1.val != root2.val) return 0; diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/LexicographicalNumbers.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/LexicographicalNumbers.java new file mode 100644 index 0000000..6184206 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/LexicographicalNumbers.java @@ -0,0 +1,51 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.hamcrest.CoreMatchers.hasItems; + +/** + * Given an integer n, return 1 - n in lexicographical order. + * + * For example, given 13, return: [1,10,11,12,13,2,3,4,5,6,7,8,9]. + * + * Please optimize your algorithm to use less time and space. The input size may be as large as 5,000,000. + * + * https://leetcode.com/problems/lexicographical-numbers/ + */ +public class LexicographicalNumbers { + public List lexicalOrder(int n) { + List l = new LinkedList<>(); + for (int i = 1; i <= 9; i++) { + dfs(n, l, i); + } + return l; + } + + private void dfs(int n, List l, int start) { + if (start > n) return; + l.add(start); + for (int i = 0; i <= 9; i++) { + dfs(n, l, start * 10 + i); + } + } + + @Test + public void test1() { + List numbers = lexicalOrder(20); + assertEquals(20, numbers.size()); + } + + @Test + public void test2() { + List numbers = lexicalOrder(10); + assertEquals(10, numbers.size()); + assertThat(numbers, hasItems(1,10,2,3,4,5,6,7,8,9)); + } +} + + diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/PathSumIII.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/PathSumIII.java new file mode 100644 index 0000000..05a540d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/PathSumIII.java @@ -0,0 +1,115 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import static org.junit.Assert.assertEquals; + +/** + * You are given a binary tree in which each node contains an integer value. + * + * Find the number of paths that sum to a given value. + * + * The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes). + * + * The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000. + * + * Example: + * + * root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8 + * + * 10 + * / \ + * 5 -3 + * / \ \ + * 3 2 11 + * / \ \ + * 3 -2 1 + * + * Return 3. The paths that sum to 8 are: + * + * 1. 5 -> 3 + * 2. 5 -> 2 -> 1 + * 3. -3 -> 11 + * + * + * + * https://leetcode.com/problems/path-sum-iii/ + */ +public class PathSumIII { + public int pathSum(TreeNode root, int sum) { + int count = 0; + if (root == null) return count; + + Queue q = new LinkedList<>(); + q.add(root); + while (!q.isEmpty()) { + TreeNode node = q.poll(); + List> paths = new ArrayList<>(); + dfs(node, paths, new ArrayList<>(), sum); + count += paths.size(); + + if (node.left != null) q.add(node.left); + if (node.right != null) q.add(node.right); + } + return count; + } + + private void dfs(TreeNode node, List> paths, List temp, int sum) { + if (node == null) return; + + temp.add(node.val); + if (sum - node.val == 0) { + paths.add(new ArrayList<>(temp)); + } + dfs(node.left, paths, temp, sum - node.val); + dfs(node.right, paths, temp, sum - node.val); + + temp.remove(temp.size() - 1); + } + + /** + * 6 + * / \ + * 3 7 + * / \ \ + * 2 5 1 + * \ + * 10 + *

+ * 6 -> 3 -> 2 -> 5 -> 7 -> 1 -> 10 + */ + @Test + public void test1() { + TreeNode root = new TreeNode(6); + root.left = new TreeNode(3); + root.right = new TreeNode(7); + + root.right.right = new TreeNode(1); + + root.left.left = new TreeNode(2); + root.left.right = new TreeNode(5); + root.right.right.right = new TreeNode(10); + + assertEquals(2, pathSum(root, 11)); + } + + @Test + public void test2() { + TreeNode root = new TreeNode(1); + root.left = new TreeNode(-2); + root.right = new TreeNode(-3); + + root.left.left = new TreeNode(1); + root.left.right = new TreeNode(3); + root.right.left = new TreeNode(-2); + + root.left.left.left = new TreeNode(-1); + + assertEquals(4, pathSum(root, -1)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/PathToSum.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/PathToSum.java index 6700046..ef0a7a6 100644 --- a/src/main/java/com/eprogrammerz/examples/algorithm/trees/PathToSum.java +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/PathToSum.java @@ -6,7 +6,9 @@ import java.util.Arrays; import java.util.List; +import static org.hamcrest.CoreMatchers.hasItems; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; /** * Given a binary tree and a sum, find all root-to-leaf paths where each path’s sum equals the given sum. @@ -31,15 +33,15 @@ public class PathToSum { public List> pathSum(TreeNode root, int target) { List> paths = new ArrayList<>(); - pathSum(root, target, paths, new ArrayList<>(), 0); + pathSum(root, target, paths, new ArrayList<>()); return paths; } - private void pathSum(TreeNode root, int target, List> paths, List path, int sum) { + private void pathSum(TreeNode root, int target, List> paths, List path) { if (root == null) return; if (root.left == null && root.right == null) { - if (sum + root.val == target) { + if (root.val == target) { path.add(root.val); paths.add(new ArrayList<>(path)); @@ -49,8 +51,8 @@ private void pathSum(TreeNode root, int target, List> paths, List< } path.add(root.val); - pathSum(root.left, target, paths, path, sum + root.val); - pathSum(root.right, target, paths, path, sum + root.val); + pathSum(root.left, target - root.val, paths, path); + pathSum(root.right, target - root.val, paths, path); path.remove(path.size() - 1); } @@ -82,7 +84,7 @@ public void testPathSum() { // add right node to rightest node on last level root.right.right.right = new TreeNode(10); List> actual2 = pathSum(root, 24); - assertEquals(Arrays.asList(Arrays.asList(6, 7, 1, 10)), actual2); + assertThat(actual2, hasItems(Arrays.asList(6, 7, 1, 10))); } } diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/PopulateNextRight.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/PopulateNextRight.java new file mode 100644 index 0000000..3718273 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/PopulateNextRight.java @@ -0,0 +1,82 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertEquals; + +/** + * You are given a perfect binary tree where all leaves are on the same level, + * and every parent has two children. The binary tree has the following definition: + * struct Node { + * int val; + * Node *left; + * Node *right; + * Node *next; + * } + * + * https://leetcode.com/problems/populating-next-right-pointers-in-each-node/ + */ +public class PopulateNextRight { + public Node connect(Node root) { + Node curr = root; + + while (curr != null && curr.left != null) { + Node runner = curr.left; + Node temp = runner; + Node prev = null; + + while (curr != null) { + runner = curr.left; + if (prev != null) { + prev.next = runner; + } + + runner.next = curr.right; + runner = runner.next; + prev = runner; + curr = curr.next; + } + + curr = temp; + } + + return root; + } + + @Test + public void test() { + Node root = new Node(1); + root.left = new Node(2); + root.right = new Node(3); + root.left.left = new Node(4); + root.left.right = new Node(5); + root.right.left = new Node(6); + root.right.right = new Node(7); + + Node populated = connect(root); + + assertEquals(3, populated.left.next.val); + assertEquals(6, populated.left.right.next.val); + } + + static class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/RemoveComments.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/RemoveComments.java new file mode 100644 index 0000000..87daab9 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/RemoveComments.java @@ -0,0 +1,74 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/remove-comments/ + */ +public class RemoveComments { + public List removeComments(String[] source) { + // read each line and look for '/' char + // look for next char + // if '/', then remove all the strings remaing to end of line + // if '*', then keep on moving until you find '*/' + List l = new ArrayList<>(); + if (source == null || source.length == 0) return l; + boolean open = false; + + StringBuilder sb = new StringBuilder(); + + for (String line: source) { + + if (!open) + sb = new StringBuilder(); + + int i = 0; + while (i < line.length()) { + if (!open && line.charAt(i) == '/' && i + 1 < line.length() && line.charAt(i + 1) == '*') { + open = true; + i++; + } else if (open && line.charAt(i) == '*' && i + 1 < line.length() && line.charAt(i + 1) == '/') { + open = false; + i++; + } else if (!open && line.charAt(i) == '/' && i + 1 < line.length() && line.charAt(i + 1) == '/') { // we can skip content after // + break; + } else if (!open) { + sb.append(line.charAt(i)); + } + i++; + } + + if (sb.length() > 0 && !open) + l.add(sb.toString()); + } + return l; + } + + @Test + public void test1() { + List expected = asList("int main()","{ "," ","int a, b, c;","a = b + c;","}"); + String[] input = {"/*Test program */", "int main()", "{ ", " // variable declaration ", "int a, b, c;", "/* This is a test", " multiline ", " comment for ", " testing */", "a = b + c;", "}"}; + assertThat(removeComments(input), is(expected)); + } + + @Test + public void test2() { + List expected = asList("ab"); + String[] input = {"a/*comment", "line", "more_comment*/b"}; + assertThat(removeComments(input), is(expected)); + } + + @Test + public void test3() { + List expected = asList("main() {"," double s = 33;"," cout << s;","}"); + String[] input = {"main() {", "/* here is commments", " // still comments */", " double s = 33;", " cout << s;", "}"}; + assertThat(removeComments(input), is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/algorithm/trees/SerializeDeserializeTree.java b/src/main/java/com/eprogrammerz/examples/algorithm/trees/SerializeDeserializeTree.java new file mode 100644 index 0000000..b951ffb --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/algorithm/trees/SerializeDeserializeTree.java @@ -0,0 +1,92 @@ +package com.eprogrammerz.examples.algorithm.trees; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * serialize given tree to string (bits representation so that it can be written in some form of memory or transmitted over the network + * + * and deserialize the string to the tree + */ +public class SerializeDeserializeTree { + // Encodes a tree to a single string. + // Time - O(n) + // Space - O(n) + public String serialize(TreeNode root) { + if (root == null) return ""; + if (root.left == null && root.right == null) return "" + root.val; + + if (root.right == null) return root.val + "(" + serialize(root.left) + ")"; + + return root.val + "(" + serialize(root.left) + ")(" + serialize(root.right) + ")"; + } + + // Decodes your encoded data to tree. + // Time - O(n) + // Space - O(n) + public TreeNode deserialize(String data) { + if ("".equals(data) || "()".equals(data)) return null; + int idx = data.indexOf("("); + + if (idx < 0) { + return new TreeNode(Integer.valueOf(data)); + } else { + String num = data.substring(0, idx); + if ("".equals(num)) return null; + TreeNode node = new TreeNode(Integer.valueOf(num)); + String remaining = data.substring(idx); + int close = closeIdx(remaining); + node.left = deserialize(remaining.substring(1, close)); + if (close + 2 < remaining.length()) + node.right = deserialize(remaining.substring(close + 2, remaining.length() - 1)); + else + node.right = null; + return node; + } + } + + private int closeIdx(String str) { + int open = 0; + for (int i = 0; i < str.length(); i++) { + if (str.charAt(i) == '(') { + open++; + } else if (str.charAt(i) == ')') { + open--; + if (open == 0) return i; + } + } + return -1; + } + + @Test + public void test() { + /** + * 2 + * / \ + * 1 3 + * / \ + * 4 5 + */ + TreeNode root = new TreeNode(2); + root.left = new TreeNode(1); + root.right = new TreeNode(3); + + root.left.left = new TreeNode(4); + root.right.right = new TreeNode(5); + + String serialize = serialize(root); + assertEquals("2(1(4))(3()(5))", serialize); + + TreeNode deserialize = deserialize(serialize); + assertTrue(sameTree(root, deserialize)); + } + + private boolean sameTree(TreeNode t1, TreeNode t2) { + if (t1 == null && t2 == null) return true; + if (t1 == null || t2 == null || (t1.val != t2.val)) return false; + + return sameTree(t1.left, t2.left) && sameTree(t1.right, t2.right); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/certification/datetime/DurationVsPeriod.java b/src/main/java/com/eprogrammerz/examples/certification/datetime/DurationVsPeriod.java index 8d4b82c..6341362 100644 --- a/src/main/java/com/eprogrammerz/examples/certification/datetime/DurationVsPeriod.java +++ b/src/main/java/com/eprogrammerz/examples/certification/datetime/DurationVsPeriod.java @@ -1,7 +1,8 @@ package com.eprogrammerz.examples.certification.datetime; -import java.time.Duration; -import java.time.Period; +import java.time.*; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalUnit; public class DurationVsPeriod { public static void main(String[] args) { @@ -13,5 +14,18 @@ public static void main(String[] args) { System.out.println(dp1); System.out.println(dp2); + + System.out.println(ZonedDateTime.now()); + System.out.println(ZonedDateTime.now(ZoneId.of("Australia/Sydney"))); + + System.out.println(Period.of(1,2,3)); // P1Y2M3D + System.out.println(Period.ofWeeks(3)); // P21D + System.out.println(Period.ofMonths(13)); // P13M + + Duration d = Duration.of(20, ChronoUnit.MINUTES); + System.out.println(d); // PT20M + + LocalDate now = LocalDate.now(); +// System.out.println(now.plus(d)); // Unsupported unit: Seconds } } diff --git a/src/main/java/com/eprogrammerz/examples/certification/i18n/DataFormatExample.java b/src/main/java/com/eprogrammerz/examples/certification/i18n/DataFormatExample.java new file mode 100644 index 0000000..1d00144 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/certification/i18n/DataFormatExample.java @@ -0,0 +1,21 @@ +package com.eprogrammerz.examples.certification.i18n; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.util.Date; + +public class DataFormatExample { + public static void main(String[] args) { + LocalDate date = LocalDate.of(2019, 7, 8); + LocalTime time = LocalTime.of(14,59); + LocalDateTime dateTime = LocalDateTime.of(date, time); + + DateTimeFormatter shortF = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT); + DateTimeFormatter mediumF = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM); + System.out.println(shortF.format(dateTime)); // 7/8/19 2:59 PM + System.out.println(mediumF.format(dateTime)); // Jul 8, 2019 2:59:00 PM + } +} diff --git a/src/main/java/com/eprogrammerz/examples/certification/i18n/NumberFormatExample.java b/src/main/java/com/eprogrammerz/examples/certification/i18n/NumberFormatExample.java new file mode 100644 index 0000000..fd5d0c8 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/certification/i18n/NumberFormatExample.java @@ -0,0 +1,21 @@ +package com.eprogrammerz.examples.certification.i18n; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.util.Locale; + +public class NumberFormatExample { + public static void main(String[] args) throws ParseException { + NumberFormat nf = NumberFormat.getCurrencyInstance(); + int price = 40; + System.out.println(nf.format(price)); // $40.00 + + nf = NumberFormat.getCurrencyInstance(new Locale("np")); + System.out.println(nf.format(price)); // suppose to print in rupees + + String amt = "$92,807.99"; + NumberFormat cf = NumberFormat.getCurrencyInstance(); + double value = (double) cf.parse(amt); + System.out.println(value); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/certification/i18n/Zoo.java b/src/main/java/com/eprogrammerz/examples/certification/i18n/Zoo.java new file mode 100644 index 0000000..5f4938c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/certification/i18n/Zoo.java @@ -0,0 +1,12 @@ +package com.eprogrammerz.examples.certification.i18n; + +import java.util.ListResourceBundle; + +public class Zoo extends ListResourceBundle { + @Override + protected Object[][] getContents() { + return new Object[][] { + {"default", "Default"} + }; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/certification/i18n/ZooOpen.java b/src/main/java/com/eprogrammerz/examples/certification/i18n/ZooOpen.java new file mode 100644 index 0000000..6849d4c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/certification/i18n/ZooOpen.java @@ -0,0 +1,24 @@ +package com.eprogrammerz.examples.certification.i18n; + +import java.util.Locale; +import java.util.ResourceBundle; + +public class ZooOpen { + public static void main(String[] args) { + Locale us = new Locale("en", "US"); + Locale france = new Locale("fr", "FR"); + + printProps(us); + + System.out.println(); + + printProps(france); + } + + private static void printProps(Locale locale) { + ResourceBundle rb = ResourceBundle.getBundle("zoo", locale); + System.out.println(rb.getString("hello")); + System.out.println(rb.getString("open")); +// System.out.println(rb.getString("default")); // this fails since there java Zoo.java can't be loaded with zoo! it has to be package.ClassName + } +} diff --git a/src/main/java/com/eprogrammerz/examples/design/AutoCompleteSystemTest.java b/src/main/java/com/eprogrammerz/examples/design/AutoCompleteSystemTest.java new file mode 100644 index 0000000..359c494 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/design/AutoCompleteSystemTest.java @@ -0,0 +1,145 @@ +package com.eprogrammerz.examples.design; + +import org.junit.Test; + +import java.util.*; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/design-search-autocomplete-system/ + */ + +public class AutoCompleteSystemTest { + @Test + public void test() { + String[] sentences = {"i love you", "island","ironman", "i love leetcode"}; + int[] times = {5,3,2,2}; + + AutocompleteSystem system = new AutocompleteSystem(sentences, times); + + assertThat(system.input('i'), is(asList("i love you", "island", "i love leetcode"))); + assertThat(system.input(' '), is(asList("i love you", "i love leetcode"))); + assertThat(system.input('a'), is(asList())); + assertThat(system.input('#'), is(asList())); + } +} + + +class AutocompleteSystem { + + private Trie trie; + + private StringBuilder curr; + public AutocompleteSystem(String[] sentences, int[] times) { + this.curr = new StringBuilder(); + this.trie = new Trie(); + + int n = sentences.length; + + for (int i = 0; i < n; i++) { + this.trie.insert(sentences[i], times[i]); + } + } + + public List input(char c) { + + if (c == '#') { + trie.insert(curr.toString(), 1); + curr = new StringBuilder(); + + return Collections.emptyList(); + } else { + curr.append(c); + } + + return this.trie.search(curr.toString()); + } +} + +class Trie { + private TrieNode root; + + public Trie() { + this.root = new TrieNode(); + } + + public void insert(String str, int count) { + TrieNode curr = root; + + List visited = new ArrayList<>(); + + for (char ch: str.toCharArray()) { + if (curr.childs[ch] == null) { + curr.childs[ch] = new TrieNode(); + } + curr = curr.childs[ch]; + visited.add(curr); + + } + + curr.times += count; + curr.sentence = str; + + for (TrieNode node: visited) { + node.update(curr); + } + + } + + public List search(String str) { + LinkedList l = new LinkedList<>(); + + TrieNode curr = root; + for (char ch: str.toCharArray()) { + if (curr.childs[ch] == null) return l; + curr = curr.childs[ch]; + } + + if (curr == null) return l; + + LinkedList top = curr.top; + + for (TrieNode hot: top) { + l.add(hot.sentence); + } + + return l; + } +} + +class TrieNode implements Comparable { + TrieNode[] childs; + String sentence; + int times; + + LinkedList top; + + public TrieNode() { + this.childs = new TrieNode[128]; + + this.top = new LinkedList<>(); + } + + @Override + public int compareTo(TrieNode that) { + int diff = that.times - this.times; + if (diff == 0) { + return this.sentence.compareTo(that.sentence); + } + return diff; + } + + public void update(TrieNode node) { + if (!top.contains(node)) { + top.add(node); + } + + Collections.sort(top); + + if (top.size() > 3) top.removeLast(); + } + +} diff --git a/src/main/java/com/eprogrammerz/examples/design/CompressedStringIteratorTest.java b/src/main/java/com/eprogrammerz/examples/design/CompressedStringIteratorTest.java new file mode 100644 index 0000000..12fe2d2 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/design/CompressedStringIteratorTest.java @@ -0,0 +1,79 @@ +package com.eprogrammerz.examples.design; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.PriorityQueue; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * https://leetcode.com/problems/design-compressed-string-iterator/ + */ +public class CompressedStringIteratorTest { + @Test + public void test() { + StringIterator iterator = new StringIterator("L1e2t1C1o1d1e1"); + + assertEquals('L', iterator.next()); + assertEquals('e', iterator.next()); + assertEquals('e', iterator.next()); + assertEquals('t', iterator.next()); + assertEquals('C', iterator.next()); + assertEquals('o', iterator.next()); + assertEquals('d', iterator.next()); + assertTrue(iterator.hasNext()); + assertEquals('e', iterator.next()); + assertFalse(iterator.hasNext()); + assertEquals(' ', iterator.next()); + iterator.next(); // return 'e' + } +} + +class StringIterator { + + private String compressed; + private char curr; + private int count; + private int i = 0; + + public StringIterator(String compressedString) { + this.compressed = compressedString; + + set(); + } + + private void set() { + if (i == compressed.length()) return; + + curr = compressed.charAt(i); + i++; + for (; i < compressed.length(); i++) { + char digit = compressed.charAt(i); + if ('0' <= digit && digit <= '9') { + count = count * 10 + (digit - '0'); + } else { + break; + } + } + } + + public char next() { + if (!hasNext()) return ' '; + + char ans = curr; + count--; + if (count == 0) { + set(); + } + + return ans; + } + + public boolean hasNext() { + if (i == compressed.length()) return count > 0; + return true; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/design/ConsistentHashTest.java b/src/main/java/com/eprogrammerz/examples/design/ConsistentHashTest.java new file mode 100644 index 0000000..061ae66 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/design/ConsistentHashTest.java @@ -0,0 +1,112 @@ +package com.eprogrammerz.examples.design; + +import org.junit.Test; + +import java.util.*; +import java.util.zip.CRC32; + +public class ConsistentHashTest { + @Test + public void test() { + List servers = Arrays.asList(new Server("10.0.0.1"), new Server("10.0.0.2")); + ConsistentHash consistentHash = new ConsistentHash(5, servers); + + Server newServer = new Server("10.0.0.3"); + consistentHash.add(newServer); + + // mapped to any of 3 servers + System.out.println(consistentHash.getServer("key0")); + System.out.println(consistentHash.getServer("key1")); + System.out.println(consistentHash.getServer("key2")); + System.out.println(consistentHash.getServer("key3")); + System.out.println(consistentHash.getServer("key4")); + + consistentHash.remove(newServer); + + // mapped to only of available 2 servers + System.out.println(consistentHash.getServer("key0")); + System.out.println(consistentHash.getServer("key1")); + System.out.println(consistentHash.getServer("key2")); + System.out.println(consistentHash.getServer("key3")); + System.out.println(consistentHash.getServer("key4")); + } +} + +class ConsistentHash { + private int numberOfVirtualNode; + + private TreeMap hashRing; + + public ConsistentHash(int numberOfVirtualNode, Collection servers) { + this.numberOfVirtualNode = numberOfVirtualNode; + this.hashRing = new TreeMap<>(); + + if (servers != null) { + for (Server server: servers) this.add(server); + } + } + + /** + * Add virtual nodes while adding physical server + * + * @param server + */ + public void add(Server server) { + for (int i = 0; i < numberOfVirtualNode; i++) { + hashRing.put(hash(i + server.getIp()), server); + } + } + + /** + * Remove all virtual nodes while removing physical server + * @param server + */ + public void remove(Server server) { + for (int i = 0; i < numberOfVirtualNode; i++) { + hashRing.remove(hash(i + server.getIp())); + } + } + + /** + * Get physical server the key mapped to + * @param key + * @return Server key belonging to + */ + public Server getServer(String key) { + if (hashRing.isEmpty()) return null; + + Long hashVal = hash(key); + + if (!hashRing.containsKey(hashVal)) { + SortedMap tailMap = hashRing.tailMap(hashVal); + hashVal = tailMap.isEmpty() ? hashRing.firstKey() : tailMap.firstKey(); + } + + return hashRing.get(hashVal); + } + + public Long hash(String key) { + CRC32 crc =new CRC32(); + crc.update(key.getBytes()); + + return crc.getValue(); + } +} + +class Server { + private String ip; + + public Server(String ip) { + this.ip = ip; + } + + public String getIp() { + return ip; + } + + @Override + public String toString() { + return ip; + } +} + diff --git a/src/main/java/com/eprogrammerz/examples/design/SearchSuggestionSystem.java b/src/main/java/com/eprogrammerz/examples/design/SearchSuggestionSystem.java new file mode 100644 index 0000000..e96458b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/design/SearchSuggestionSystem.java @@ -0,0 +1,103 @@ +package com.eprogrammerz.examples.design; + +import org.junit.Test; + +import java.util.*; + +import static java.util.Arrays.asList; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * https://leetcode.com/problems/search-suggestions-system/ + */ +public class SearchSuggestionSystem { + public List> suggestedProducts(String[] products, String searchWord) { + Trie trie = new Trie(); + + for (String product: products) { + trie.insert(product); + } + + List> l = new ArrayList<>(); + + for (int i = 1; i <= searchWord.length(); i++) { + l.add(trie.search(searchWord.substring(0, i))); + } + + return l; + } + + class Trie { + TrieNode root; + + Trie() { + this.root = new TrieNode(); + } + + + public void insert(String word) { + + TrieNode curr = root; + + List visited = new ArrayList<>(); + + for (char ch: word.toCharArray()) { + if (curr.child[ch - 'a'] == null) { + curr.child[ch - 'a'] = new TrieNode(); + } + curr = curr.child[ch - 'a']; + + visited.add(curr); + } + + for (TrieNode node: visited) { + node.updateTop(word); + } + } + + public List search(String str) { + if (str.length() == 0) return Collections.emptyList(); + TrieNode curr = root; + for (char ch: str.toCharArray()) { + if (curr.child[ch - 'a'] == null) { + return Collections.emptyList(); + } else { + curr = curr.child[ch - 'a']; + + } + } + + return new LinkedList<>(curr.top); + } + } + class TrieNode { + TrieNode[] child; + LinkedList top; + + TrieNode() { + this.child = new TrieNode[26]; + this.top = new LinkedList<>(); + } + + public void updateTop(String word) { + if (!top.contains(word)) { + top.add(word); + } + + top.sort(Comparator.naturalOrder()); + + if (top.size() > 3) { + top.removeLast(); + } + } + } + + @Test + public void test() { + List> expected = asList(asList("mobile","moneypot","monitor"), + asList("mobile","moneypot","monitor"), asList("mouse","mousepad"), + asList("mouse","mousepad"), asList("mouse","mousepad")); + assertThat(suggestedProducts(new String[] {"mobile","mouse","moneypot","monitor","mousepad"} , "mouse"), is(expected)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/design/SnakeGameTest.java b/src/main/java/com/eprogrammerz/examples/design/SnakeGameTest.java new file mode 100644 index 0000000..30705fd --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/design/SnakeGameTest.java @@ -0,0 +1,105 @@ +package com.eprogrammerz.examples.design; + +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/design-snake-game/ + */ + +public class SnakeGameTest { + @Test + public void test() { + SnakeGame game = new SnakeGame(2,2, new int[][] {{1,1}, {0,0}}); + + assertEquals(0, game.move("R")); + assertEquals(1, game.move("D")); + assertEquals(1, game.move("L")); + assertEquals(2, game.move("U")); + assertEquals(2, game.move("R")); + } +} + +class SnakeGame { + + /** Initialize your data structure here. + @param width - screen width + @param height - screen height + @param food - A list of food positions + E.g food = [[1,1], [1,0]] means the first food is positioned at [1,1], the second is at [1,0]. */ + // q to track co-ordinates + // add when going to new cell, and poll + + private int r; + private int c; + + private int score; + private int[][] food; + private Deque curr; + + public SnakeGame(int width, int height, int[][] food) { + this.r = height; + this.c = width; + this.food = food; + + this.curr = new ArrayDeque<>(); + this.curr.addFirst(new int[] {0, 0}); + + } + + /** Moves the snake. + @param direction - 'U' = Up, 'L' = Left, 'R' = Right, 'D' = Down + @return The game's score after the move. Return -1 if game over. + Game over when snake crosses the screen boundary or bites its body. */ + public int move(String direction) { + int[] head = curr.getFirst(); + + int row = head[0]; + int col = head[1]; + + switch(direction) { + case "U": + row--; + break; + case "L": + col--; + break; + case "R": + col++; + break; + case "D": + row++; + break; + } + + if (row == r || row < 0 || col == c || col < 0) return -1; + + if (score < food.length && row == food[score][0] && col == food[score][1]) { + score++; + } else { + + // update snake + curr.removeLast(); + } + + if (isPartOfSnake(row, col)) return -1; + + curr.addFirst(new int[] {row, col}); + + return score; + } + + private boolean isPartOfSnake(int row, int col) { + Iterator itr = curr.iterator(); + + while (itr.hasNext()) { + int[] p = itr.next(); + if (row == p[0] && col == p[1]) return true; + } + + return false; + } +} \ No newline at end of file diff --git a/src/main/java/com/eprogrammerz/examples/design/TwitterTester.java b/src/main/java/com/eprogrammerz/examples/design/TwitterTester.java new file mode 100644 index 0000000..f5d4ce1 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/design/TwitterTester.java @@ -0,0 +1,114 @@ +package com.eprogrammerz.examples.design; + +import org.junit.Test; + +import java.time.LocalDateTime; +import java.util.*; + +import static org.hamcrest.CoreMatchers.hasItems; +import static org.hamcrest.MatcherAssert.assertThat; + +public class TwitterTester { + + @Test + public void test() { + Twitter twitter = new Twitter(); + twitter.postTweet(1,5); + twitter.postTweet(1,3); + twitter.postTweet(1,101); + twitter.postTweet(1,13); + twitter.postTweet(1,10); + twitter.postTweet(1,2); + twitter.postTweet(1,94); + twitter.postTweet(1,505); + twitter.postTweet(1,333); + + System.out.println(twitter.getNewsFeed(1)); + assertThat(twitter.getNewsFeed(1), hasItems(333, 505, 94, 2, 10, 13, 101, 3, 5)); + } +} + + +class Twitter { + + private Map> m1; + private Map> m2; + + private long timestamp; + /** Initialize your data structure here. */ + public Twitter() { + this.m1 = new HashMap<>(); + this.m2 = new HashMap<>(); + } + + /** Compose a new tweet. */ + public void postTweet(int userId, int tweetId) { + if (!m1.containsKey(userId)) { + m1.put(userId, new ArrayList<>()); + } + if (!m2.containsKey(userId)) { + m2.put(userId, new HashSet<>()); + } + this.m1.get(userId).add(new Tweet(tweetId, ++timestamp)); + } + + /** Retrieve the 10 most recent tweet ids in the user's news feed. Each item in the news feed must be posted by users who the user followed or by the user herself. Tweets must be ordered from most recent to least recent. */ + public List getNewsFeed(int userId) { + PriorityQueue pq = new PriorityQueue<>( + (t1, t2) -> (int) (t1.dateCreated - t2.dateCreated)); + List self = m1.get(userId); + if (self != null && !self.isEmpty()) { + for (Tweet tweet: self) { + pq.offer(tweet); + if (pq.size() > 10) pq.poll(); + } + + } + + Set followees = m2.get(userId); + if (followees != null) { + for (int followee: followees) { + List tweets = m1.get(followee); + if (tweets == null) continue; + + for (Tweet tweet: tweets) { + pq.add(tweet); + if (pq.size() > 10) pq.poll(); + } + } + } + + LinkedList posts = new LinkedList<>(); + while (!pq.isEmpty()) { + posts.addFirst(pq.poll().tweetId); + } + return posts; + } + + /** Follower follows a followee. If the operation is invalid, it should be a no-op. */ + public void follow(int followerId, int followeeId) { + if (followerId == followeeId) return; + + if (!m2.containsKey(followerId)) { + m2.put(followerId, new HashSet<>()); + } + this.m2.get(followerId).add(followeeId); + } + + /** Follower unfollows a followee. If the operation is invalid, it should be a no-op. */ + public void unfollow(int followerId, int followeeId) { + if (!m2.containsKey(followerId)) return; + m2.get(followerId).remove(followeeId); + } + + + class Tweet { + int tweetId; + long dateCreated; + + Tweet(int tweetId, long dateCreated) { + this.tweetId = tweetId; + this.dateCreated = dateCreated; + } + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/cache/LRUCache.java b/src/main/java/com/eprogrammerz/examples/ds/cache/LRUCache.java index dd8d34e..26358bc 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/cache/LRUCache.java +++ b/src/main/java/com/eprogrammerz/examples/ds/cache/LRUCache.java @@ -24,12 +24,13 @@ */ public class LRUCache { - private class Node { + + private class Node { K key; V value; - Node next; - Node prev; + Node next; + Node prev; Node(K key, V value) { this.key = key; @@ -42,6 +43,91 @@ public String toString() { } } + private Map> map; + private DDList list; + private int capacity; + + private int size; + + public LRUCache(int capacity) { + this.capacity = capacity; + this.map = new HashMap<>(); + this.list = new DDList(); + } + + public V get(K key) { + Node node = map.get(key); + + if (node == null) return null; + + list.removeNode(node); + list.addToHead(node); + + return node.value; + } + + public void put(K key, V value) { + Node node = map.get(key); + + if (node != null) { + node.value = value; + + list.removeNode(node); + list.addToHead(node); + + return; + } + + node = new Node<>(key, value); + + if (size == capacity) { + Node last = list.removeTail(); + map.remove(last.key); + + size--; + } + + list.addToHead(node); + size++; + map.put(key, node); + } + + class DDList { + Node head; + Node tail; + + DDList() { + this.head = new Node(0, 0); + this.tail = new Node(0, 0); + this.head.next = tail; + this.tail.prev = head; + } + + public void addToHead(Node node) { + node.next = head.next; + node.prev = head; + + head.next.prev = node; + head.next = node; + } + + public void removeNode(Node node) { + node.next.prev = node.prev; + node.prev.next = node.next; + + } + + public Node removeTail() { + if (tail.prev == head) return null; + Node node = tail.prev; + removeNode(node); + + return node; + } + } +} + +/* private int size; private Map> map; @@ -107,5 +193,6 @@ private void removeNode(Node node) { if (tail == node) tail = node.prev; if (head == node) head = node.next; } + } +*/ -} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/AddTwoNumII.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/AddTwoNumII.java new file mode 100644 index 0000000..16842d2 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/AddTwoNumII.java @@ -0,0 +1,72 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +/** + * https://leetcode.com/problems/add-two-numbers-ii/ + *

+ * Input: (7 -> 2 -> 4 -> 3) + (5 -> 6 -> 4) + * Output: 7 -> 8 -> 0 -> 7 + */ +public class AddTwoNumII { + + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + int len1 = 0; + int len2 = 0; + ListNode h1 = l1; + while (h1 != null) { + len1++; + h1 = h1.next; + } + + ListNode h2 = l2; + while (h2 != null) { + len2++; + h2 = h2.next; + } + ListNode sum = traverse(l1, l2, len1, len2); + return sum.val == 0 ? sum.next: sum; + } + + private ListNode traverse(ListNode l1, ListNode l2, int len1, int len2) { + if (l1 == null && l2 == null) return new ListNode(0); + ListNode next; + int sum; + if (len1 == len2) { + next = traverse(l1.next, l2.next, len1 - 1, len2 - 1); + sum = l1.val + l2.val + next.val; + } else if (len1 > len2) { + next = traverse(l1.next, l2, len1 - 1, len2); + sum = l1.val + next.val; + } else { + next = traverse(l1, l2.next, len1, len2 - 1); + sum = l2.val + next.val; + } + + ListNode node = new ListNode(sum / 10); + next.val = sum % 10; + + node.next = next; + + return node; + } + + @Test + public void test() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(3); + ListNode n3 = new ListNode(8); + n1.next = n2; + n2.next = n3; + + ListNode m1 = new ListNode(2); + ListNode m2 = new ListNode(4); + m1.next = m2; + + ListNode sum = addTwoNumbers(n1, m1); + assertEquals("1 -> 6 -> 2", printList(sum)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/FirstUniqueNumberInStream.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/FirstUniqueNumberInStream.java new file mode 100644 index 0000000..a8fda20 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/FirstUniqueNumberInStream.java @@ -0,0 +1,147 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import lombok.val; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.*; + +/** + * Design a data structure that support the following methods: + * + * public class Stream { + * + * public Stream() { + * // do intialization if necessary + * } + * + * + * // Adds integer num to a stream of integers. + * + * public void add(int num) { + * // write your code here + * } + * + * * Returns the first unique integer in the stream if found else return null. + * + public Integer getFirstUnique() { + // write your code here + } + +head tail + | | + v V + 3 -> 4 + * Exaple: + Stream s = new Stream(); + s.add(2); + s.getFirstUnique(); // 2 + s.add(2); + s.getFirstUnique(); // null + s.add(3); + s.getFirstUnique(); // 3 + s.add(4); + s.getFirstUnique(); // 3 + s.add(3); + s.getFirstUnique(); // 4 + */ +public class FirstUniqueNumberInStream { + @Test + public void test1() { + Stream s = new Stream(); + s.add(2); + assertThat(s.getFirstUnique(), equalTo(2)); // 2 + s.add(2); + assertNull(s.getFirstUnique()); // null + s.add(3); + assertThat(s.getFirstUnique(), equalTo(3)); // 3 + s.add(4); + assertThat(s.getFirstUnique(), equalTo(3)); // 3 + s.add(3); + assertThat(s.getFirstUnique(), equalTo(4)); // 4 + } +} + +class Stream { + private Map map; + private Node uniqueHead; + private Node uniqueTail; + + public Stream() { + // do intialization if necessary + this.map = new HashMap<>(); + this.uniqueHead = null; + } + + /** + * Adds integer num to a stream of integers. + */ + public void add(int num) { + Node existing = this.map.get(num); + + // there has not been added any entry with num + if (existing == null) { + Node node = new Node(num); + if (uniqueHead == null) { + this.uniqueHead = node; + this.uniqueTail = node; + } else { + node.prev = uniqueTail; + this.uniqueTail.next = node; + this.uniqueTail = node; + } + map.put(num, node); + } else if (existing.unique) { + //remove from list + if (uniqueHead == existing) { + if (uniqueHead == uniqueTail) { + uniqueHead = null; + uniqueTail = null; + } else { + Node nextHead = uniqueHead.next; + uniqueHead.next = null; + uniqueHead = nextHead; + uniqueHead.prev = null; + } + } else if (uniqueTail == existing) { + Node nextTail = uniqueTail.prev; + uniqueTail.prev = null; + uniqueTail = nextTail; + uniqueTail.next = null; + } else { + existing.prev.next = existing.next; + existing.next.prev = existing.prev; + existing.prev = null; + existing.next = null; + } + // update on map + existing.unique = false; + } else { + // do nothing as entry will be there in map, but not in list + } + + } + + /** + * Returns the first unique integer in the stream if found else return null. + */ + public Integer getFirstUnique() { + if (this.uniqueHead == null) return null; + return uniqueHead.val; + } + + class Node { + int val; + Node next; + Node prev; + boolean unique; + + Node(int val) { + this.val = val; + this.unique = true; + } + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/KReverseLinkedList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/KReverseLinkedList.java new file mode 100644 index 0000000..421144e --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/KReverseLinkedList.java @@ -0,0 +1,113 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +/** + * Given a singly linked list and an integer K, reverses the nodes of the + * + * list K at a time and returns modified linked list. + * + * NOTE : The length of the list is divisible by K + * Example : + * + * Given linked list 1 -> 2 -> 3 -> 4 -> 5 -> 6 and K=2, + * + * You should return 2 -> 1 -> 4 -> 3 -> 6 -> 5 + * + * Try to solve the problem using constant extra space. + */ +public class KReverseLinkedList { + public ListNode reverseList(ListNode head, int k) { + + ListNode current = head; + ListNode previous = null; + ListNode next = null; + + if (isGroup(current, k)) { + int count = k; + while (count-- > 0 && current != null) { + next = current.next; + current.next = previous; + previous = current; + current = next; + } + } else { + return head; + } + + if (current != null) { + if (isGroup(current, k)) { + head.next = reverseList(current, k); + } else { + head.next = next; + } + } + return previous == null ? current: previous; + } + + private boolean isGroup(ListNode node, int k) { + int count = 0; + while (node != null) { + count++; + node = node.next; + if (count == k) return true; + } + return false; + } + + @Test + public void testReverse1() { + // 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 ->8 -> 9 + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(6); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(8); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + + ListNode res = reverseList(n1, 2); // 2 -> 1 -> 4 -> 3 -> 6 -> 5 -> 8 -> 7 -> 9 + assertEquals("2 -> 1 -> 4 -> 3 -> 6 -> 5 -> 8 -> 7 -> 9", printList(res)); + } + + @Test + public void testReverse2() { + // 1 -> 2 -> 3 -> 4 -> 5 + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + + ListNode res = reverseList(n1, 3); // 3 -> 2 -> 1 -> 4 -> 5 + assertEquals("3 -> 2 -> 1 -> 4 -> 5", printList(res)); + } + + @Test + public void testReverse3() { + // 1 -> 2 + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + n1.next = n2; + + ListNode res = reverseList(n1, 3); // 1 -> 2 + assertEquals("1 -> 2", printList(res)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ListNode.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ListNode.java new file mode 100644 index 0000000..7882ec8 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ListNode.java @@ -0,0 +1,15 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +public class ListNode { + int val; + ListNode next; + + ListNode(int val) { + this.val = val; + } + + @Override + public String toString() { + return "(" + val + ")"; + } +} \ No newline at end of file diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ListUtil.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ListUtil.java new file mode 100644 index 0000000..ed15899 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ListUtil.java @@ -0,0 +1,17 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +public class ListUtil { + + public static String printList(ListNode res) { + StringBuilder sb = new StringBuilder(); + if (res == null) return sb.toString(); + + while (res.next != null) { + sb.append(res.val); + sb.append(" -> "); + res = res.next; + } + sb.append(res.val); + return sb.toString(); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/MergeKSortedList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/MergeKSortedList.java new file mode 100644 index 0000000..c03c82c --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/MergeKSortedList.java @@ -0,0 +1,114 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import java.util.PriorityQueue; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +public class MergeKSortedList { + public ListNode mergeKLists(ListNode[] lists) { + if (lists == null || lists.length == 0) return null; + + return mergeKLists(lists, 0, lists.length - 1); + } + + private ListNode mergeKLists(ListNode[] lists, int start, int end) { + if (end == start) + return lists[end]; + int mid = start + (end - start) / 2; + ListNode a = mergeKLists(lists, start, mid); + ListNode b = mergeKLists(lists, mid + 1, end); + return mergeTwoList(a, b); + } + + private ListNode mergeTwoList(ListNode l1, ListNode l2) { + if (l1 == null) return l2; + if (l2 == null) return l1; + + ListNode dummy = new ListNode(-1); + ListNode runner = dummy; + + while (l1 != null && l2 != null) { + if (l1.val > l2.val) { + runner.next = l2; + runner = runner.next; + l2 = l2.next; + } else { + runner.next = l1; + runner = runner.next; + l1 = l1.next; + } + } + + if (l1 != null) { + runner.next = l1; + } + + if (l2 != null) { + runner.next = l2; + } + return dummy.next; + } + + @Test + public void test() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(3); + ListNode n3 = new ListNode(8); + n1.next = n2; + n2.next = n3; + + ListNode m1 = new ListNode(2); + ListNode m2 = new ListNode(4); + m1.next = m2; + + ListNode[] lists = new ListNode[] { n1, m1}; + ListNode res = mergeKLists(lists); + assertEquals("1 -> 2 -> 3 -> 4 -> 8", printList(res)); + } + + public ListNode mergeKListsPQ(ListNode[] lists) { + if (lists == null || lists.length == 0) return null; + + PriorityQueue pq = new PriorityQueue<>((n1, n2) -> n1.val - n2.val); + + ListNode dummy = new ListNode(-1); + ListNode runner = dummy; + + for (int i = 0; i < lists.length; i++) { + if (lists[i] != null) { + pq.add(lists[i]); + } + } + + while (!pq.isEmpty()) { + ListNode node = pq.poll(); + runner.next = node; + runner = runner.next; + + if (node.next != null) { + pq.add(node.next); + } + } + return dummy.next; + } + + @Test + public void testBetter() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(3); + ListNode n3 = new ListNode(8); + n1.next = n2; + n2.next = n3; + + ListNode m1 = new ListNode(2); + ListNode m2 = new ListNode(4); + m1.next = m2; + + ListNode[] lists = new ListNode[] { n1, m1}; + ListNode res = mergeKListsPQ(lists); + assertEquals("1 -> 2 -> 3 -> 4 -> 8", printList(res)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/MyLinkedList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/MyLinkedList.java index 9c03951..4086fdc 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/MyLinkedList.java +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/MyLinkedList.java @@ -2,12 +2,21 @@ public class MyLinkedList { private Node head; + private Node tail; + private int size; public MyLinkedList() {} public void addFirst(T t) { - this.head = new Node<>(t, this.head); + Node node = new Node<>(t); + if (head == null) { + head = node; + tail = node; + } else { + node.next = head; + head = node; + } size++; } @@ -20,27 +29,19 @@ public void addLast(T t) { Node node = new Node<>(t); if (head == null) { head = node; + tail = node; + } else { + tail.next = node; + tail = node; } - Node current = head; - - while (current.next != null) { - current = current.next; - } - current.next = node; - // increment size size++; } public T getLast() { if (head == null) return null; - Node node = head; - - while (node.next != null) { - node = node.next; - } - return node.data; + return tail.data; } public T getAt(int idx) { @@ -134,11 +135,6 @@ public Node(T data) { this.next = null; } - public Node(T data, Node next) { - this.data = data; - this.next = next; - } - @Override public String toString() { return "(" + data + ")"; diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/NextGreaterNode.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/NextGreaterNode.java new file mode 100644 index 0000000..17b05fe --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/NextGreaterNode.java @@ -0,0 +1,40 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import java.util.ArrayList; +import java.util.List; +import java.util.Stack; + +/** + * https://leetcode.com/problems/next-greater-node-in-linked-list/ + */ +public class NextGreaterNode { + public int[] nextLargerNodes(ListNode head) { + List l = new ArrayList<>(); + while (head != null) { + l.add(head.val); + head = head.next; + } + + int[] res = new int[l.size()]; + + // to track monotone integer val of nodes + Stack stack = new Stack<>(); + + for (int i = l.size() - 1; i >= 0; i--) { + int curr = l.get(i); + + while (!stack.isEmpty() && curr >= stack.peek()) { + stack.pop(); + } + if (stack.isEmpty()) { + res[i] = 0; + } else { + res[i] = stack.peek(); + } + + stack.push(curr); + } + + return res; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/PalindromeCheck.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/PalindromeCheck.java new file mode 100644 index 0000000..83d9144 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/PalindromeCheck.java @@ -0,0 +1,116 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +public class PalindromeCheck { + public boolean isPalindrome(ListNode head) { + if (head == null) return false; + boolean isEven = isEven(head); + + ListNode mid = mid(head); + + ListNode l2 = mid.next; + mid.next = null; + ListNode l1 = reverse(head); + + if (!isEven) l1 = l1.next; + + while (l1 != null && l2 != null) { + if (l1.val != l2.val) return false; + l1 = l1.next; + l2 = l2.next; + } + + if (l1 != null || l2 != null) return false; + return true; + } + + private ListNode reverse(ListNode node) { + if (node == null) return node; + ListNode prev = null; + while (node != null) { + ListNode temp = node.next; + node.next = prev; + prev = node; + node = temp; + } + return prev; + } + + private boolean isEven(ListNode node) { + if (node == null) return false; + + ListNode slow = node; + ListNode fast = node.next; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + return fast != null; + } + + private ListNode mid(ListNode node) { + if (node == null) return null; + + ListNode slow = node; + ListNode fast = node.next; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } + + @Test + public void testPalindrome1() { + // 7 -> 2 -> 5 -> 3 -> 5 -> 2 -> 7 + ListNode head = new ListNode(7); + ListNode node1 = new ListNode(2); + ListNode node2 = new ListNode(5); + ListNode node3 = new ListNode(3); + ListNode node4 = new ListNode(5); + ListNode node5 = new ListNode(2); + ListNode node6 = new ListNode(7); + head.next = node1; + node1.next = node2; + node2.next = node3; + node3.next = node4; + node4.next = node5; + node5.next = node6; + + assertTrue(isPalindrome(head)); + } + + @Test + public void testPalindrome2() { + // 7 -> 2 -> 2 -> 7 + ListNode head = new ListNode(7); + ListNode node1 = new ListNode(2); + ListNode node2 = new ListNode(2); + ListNode node3 = new ListNode(7); + head.next = node1; + node1.next = node2; + node2.next = node3; + + assertTrue(isPalindrome(head)); + } + + @Test + public void testPalindrome3() { + // 7 -> 2 -> 2 -> 7 + ListNode head = new ListNode(7); + ListNode node1 = new ListNode(2); + ListNode node2 = new ListNode(2); + ListNode node3 = new ListNode(5); + head.next = node1; + node1.next = node2; + node2.next = node3; + + assertFalse(isPalindrome(head)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/PartitionList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/PartitionList.java new file mode 100644 index 0000000..ebee85d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/PartitionList.java @@ -0,0 +1,123 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +/** + * Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x. + * + * You should preserve the original relative order of the nodes in each of the two partitions. + * + * Example: + * + * Input: head = 1->4->3->2->5->2, x = 3 + * Output: 1->2->2->4->3->5 + */ +public class PartitionList { + /** + * O(n) - time + * O(1) - space + * @param head + * @param x + * @return + */ + public ListNode partition(ListNode head, int x) { + if (head == null) return null; + ListNode less = head; + ListNode lessPrev = null; + ListNode ge = head; + ListNode gePrev = null; + + while (less != null && ge != null) { + if(ge.val >= x) { + if (less != ge && less.val < x) { + // change pointers + ListNode newLess = less.next; + lessPrev.next = less.next; + less.next = ge; + + if (gePrev != null) { + gePrev.next = less; + gePrev = gePrev.next; + } else { + head = less; + gePrev = less; + } + less = newLess; + } else { + lessPrev = less; + less = less.next; + } + } else { + lessPrev = less; + less = less.next; + gePrev = ge; + ge = ge.next; + } + } + return head; + } + + @Test + public void test1() { + // 1 -> 4 -> 3 -> 2 -> 5 -> 2 + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(4); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(2); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(2); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + + ListNode res = partition(n1, 3); + assertEquals("1 -> 2 -> 2 -> 4 -> 3 -> 5", printList(res)); + } + + @Test + public void test2() { + // 1 -> 4 -> 3 -> 2 -> 5 -> 2 -> 7 -> 8 -> 9 + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(4); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(2); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(2); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(8); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + + ListNode res = partition(n1, 4); + assertEquals("1 -> 3 -> 2 -> 2 -> 4 -> 5 -> 7 -> 8 -> 9", printList(res)); + } + + @Test + public void test3() { + // 2 -> 1 + ListNode n1 = new ListNode(4); + ListNode n2 = new ListNode(3); + ListNode n3 = new ListNode(2); + ListNode n4 = new ListNode(1); + ListNode n5 = new ListNode(1); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + + ListNode res = partition(n1, 2); + assertEquals("1 -> 1 -> 4 -> 3 -> 2", printList(res)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/RemoveNthNodeFromLast.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/RemoveNthNodeFromLast.java new file mode 100644 index 0000000..73ebd65 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/RemoveNthNodeFromLast.java @@ -0,0 +1,69 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +public class RemoveNthNodeFromLast { + public ListNode removeNthFromEnd(ListNode head, int n) { + ListNode node = head; + + ListNode fast = head; + for (int i = 0; i < n; i++) { + fast = fast.next; + } + + while (fast != null && fast.next != null) { + node = node.next; + fast = fast.next; + } + + if (fast == null) { + head = head.next; + } else { + + node.next = node.next != null ? node.next.next : null; + } + + return head; + } + + @Test + public void testRemoveNthFromEnd1() { +// 1 -> 2 -> 3 -> 4 -> 5 -> 6 + ListNode head = new ListNode(1); + ListNode node1 = new ListNode(2); + ListNode node2 = new ListNode(3); + ListNode node3 = new ListNode(4); + ListNode node4 = new ListNode(5); + head.next = node1; + node1.next = node2; + node2.next = node3; + node3.next = node4; + + ListNode res = removeNthFromEnd(head, 2); + assertEquals("1 -> 2 -> 3 -> 5", printList(res)); + } + + + @Test + public void testRemoveNthFromEnd2() { + // 1 -> 2 + ListNode head = new ListNode(1); + ListNode node1 = new ListNode(2); + head.next = node1; + + ListNode res = removeNthFromEnd(head, 2); + assertEquals("2", printList(res)); + } + + @Test + public void testRemoveNthFromEnd3() { + // 1 -> 2 + ListNode head = new ListNode(1); + + ListNode res = removeNthFromEnd(head, 1); + assertEquals("", printList(res)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ReverseList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ReverseList.java new file mode 100644 index 0000000..16f9e36 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ReverseList.java @@ -0,0 +1,48 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +/** + * Reverse a singly linked list. + * + * Example: + * + * Input: 1->2->3->4->5->NULL + * Output: 5->4->3->2->1->NULL + */ +public class ReverseList { + public ListNode reverseList(ListNode head) { + if (head == null || head.next == null) return head; + ListNode revHead = reverseList(head.next); + head.next.next = head; + head.next = null; + return revHead; + } + + @Test + public void testReverse() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(6); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(8); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + + ListNode res = reverseList(n1); + assertEquals("9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1", printList(res)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ReverseListII.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ReverseListII.java new file mode 100644 index 0000000..36b885d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/ReverseListII.java @@ -0,0 +1,113 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import java.util.List; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +/** + * Reverse a linked list from position m to n. Do it in-place and in one-pass. + * + * For example: + * Given 1->2->3->4->5->NULL, m = 2 and n = 4, + * + * return 1->4->3->2->5->NULL. + * + * https://leetcode.com/problems/reverse-linked-list-ii/ + */ +public class ReverseListII { + public ListNode reverseBetween(ListNode head, int m, int n) { + ListNode prev = null; + ListNode next = null; + + // if m == 1, then head needed to be updated + + int i = 1; + + ListNode runner = head; + while (runner != null) { + if (i == m - 1) { + prev = runner; + } + + if (i == n) { + next = runner.next; + break; + } + + runner = runner.next; + i++; + } + + + ListNode part = prev == null ? head: prev.next; + + if (prev != null) + prev.next = null; + + runner.next = null; + + ListNode rhead = reverse(part); + + if (prev != null) + prev.next = rhead; + else head = rhead; + + while (rhead.next != null) { + rhead = rhead.next; + } + + rhead.next = next; + + return head; + } + + private ListNode reverse(ListNode head) { + if (head.next == null) return head; + + ListNode node = reverse(head.next); + + head.next.next = head; + head.next = null; + + return node; + } + + @Test + public void testReverse() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(6); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(8); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + + ListNode res = reverseBetween(n1, 2, 4); + assertEquals("1 -> 4 -> 3 -> 2 -> 5 -> 6 -> 7 -> 8 -> 9", printList(res)); + } + + @Test + public void testReverse2() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + n1.next = n2; + n2.next = n3; + + ListNode res = reverseBetween(n1, 2 ,3); + assertEquals("1 -> 3 -> 2", printList(res)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/RotateList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/RotateList.java new file mode 100644 index 0000000..7f2db62 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/RotateList.java @@ -0,0 +1,73 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class RotateList { + public ListNode rotateRight(ListNode A, int B) { + // find size so that we can find the node for the head in resulting list + int size = getSize(A); + + ListNode node = A; + ListNode prev = node; + ListNode firstHalf = prev; + + for (int i = 0; i < size; i++) { + prev = node; // prev = 3 + node = node.next; // node = 4 + int newIdx = (i + B + 1) % size; + if (newIdx == 0) { + break; + } + } + prev.next = null; + ListNode half = node; + ListNode head = node; + + if (half != null) { + while (half.next != null) { + half = half.next; + } + half.next = firstHalf; + } else { + head = firstHalf; + } + + return head; + } + + private int getSize(ListNode node) { + ListNode n = node; + int size = 0; + while (n != null) { + size++; + n = n.next; + } + return size; + } + + @Test + public void testRotateRight() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(6); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(8); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + + ListNode res = rotateRight(n1, 3); // (7)(8)(9)(1)(2)(3)(4)(5)(6) + assertEquals(7, res.val); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SortLinkedList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SortLinkedList.java new file mode 100644 index 0000000..f4111bf --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SortLinkedList.java @@ -0,0 +1,112 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + + +import org.junit.Test; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +/** + * Sort a linked list in O(n log n) time using constant space complexity. + * + * Example 1: + * + * Input: 4->2->1->3 + * Output: 1->2->3->4 + */ +public class SortLinkedList { + public ListNode sortList(ListNode head) { + if (head == null || head.next == null) return head; + + ListNode left = findMid(head); + + ListNode right = left.next; + left.next = null; + + left = sortList(head); + right = sortList(right); + + // now merge left and right + ListNode dummy = new ListNode( - 1); + ListNode runner = dummy; + + while (left != null && right != null) { + if (left.val <= right.val) { + runner.next = left; + left = left.next; + } else { + runner.next = right; + right = right.next; + } + runner = runner.next; + } + + if (left != null) { + runner.next = left; + } + + if (right != null) { + runner.next = right; + } + + return dummy.next; + } + + private ListNode findMid(ListNode head) { + if (head == null || head.next == null) return head; + ListNode slow = head; + ListNode fast = head.next; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } + + @Test + public void test1() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(8); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(6); + ListNode n6 = new ListNode(5); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(2); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + + ListNode res = sortList(n1); + assertEquals("1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9", printList(res)); + } + + @Test + public void test2() { + ListNode n1 = new ListNode(3); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(1); + n1.next = n2; + n2.next = n3; + + ListNode res = sortList(n1); + assertEquals("1 -> 2 -> 3", printList(res)); + } + + @Test + public void test3() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(-1); + n1.next = n2; + + ListNode res = sortList(n1); + assertEquals("-1 -> 1", printList(res)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SumList.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SumList.java index 3816d82..d3ddf78 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SumList.java +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SumList.java @@ -2,8 +2,11 @@ import org.junit.Test; +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + public class SumList { - private Node sumList(Node h1, Node h2) { + public Node sumList(Node h1, Node h2) { Node result = null; Node carrier = null; @@ -69,4 +72,69 @@ public void testSumList() { } // prints 219 } + + /** + * You are given two non-empty linked lists representing two non-negative integers. + * The digits are stored in reverse order and each of their nodes contain a single digit. + * Add the two numbers and return it as a linked list. + * + * You may assume the two numbers do not contain any leading zero, except the number 0 itself. + * + * Example: + * + * Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) + * Output: 7 -> 0 -> 8 + * Explanation: 342 + 465 = 807. + * @param l1 + * @param l2 + * @return + */ + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + int carry = 0; + + ListNode result = new ListNode(-1); + + ListNode last = result; + + while(l1 != null || l2 != null) { + int x = l1 != null ? l1.val : 0; + int y = l2 != null ? l2.val : 0; + int sum = x + y + carry; + + if (l1 != null) l1 = l1.next; + if (l2 != null) l2 = l2.next; + carry = sum / 10; + sum = sum % 10; + + last.next = new ListNode(sum); + last = last.next; + } + + if(carry != 0) { + last.next = new ListNode(carry); + } + return result.next; + } + + @Test + public void testSumList2() { + // 617 + // presented in reverse order 7 -> 1 -> 6 + ListNode n1 = new ListNode(7); + ListNode n2 = new ListNode(1); + ListNode n3 = new ListNode(6); + n1.next = n2; + n2.next = n3; + + // 295 + // 5 -> 9 -> 2 + ListNode na = new ListNode(5); + ListNode nb = new ListNode(9); + ListNode nc = new ListNode(2); + na.next = nb; + nb.next = nc; + + ListNode sum = addTwoNumbers(n1, na); // 912 + assertEquals("2 -> 1 -> 9", printList(sum)); + } } diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SwapPair.java b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SwapPair.java new file mode 100644 index 0000000..b93bf92 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/linkedList/SwapPair.java @@ -0,0 +1,95 @@ +package com.eprogrammerz.examples.ds.custom.linkedList; + +import org.junit.Test; + +import static com.eprogrammerz.examples.ds.custom.linkedList.ListUtil.printList; +import static org.junit.Assert.assertEquals; + +/** + * Given a linked list, swap every two adjacent nodes and return its head. + * + * e.g. for a list 1-> 2 -> 3 -> 4, one should return the head of list as 2 -> 1 -> 4 -> 3. + */ +public class SwapPair { + public ListNode swapPairs(ListNode A) { + // temp = current.next + // prev.next = current.next + // current.next = prev + // current = temp + + ListNode prev = null; + ListNode head = A.next; + if (head == null) return A; + + ListNode current = A; + while (current != null && current.next != null) { + + ListNode temp = current.next; + current.next = current.next.next; + temp.next = current; + if (prev != null) prev.next = temp; + prev = current; + current = current.next; + } + return head; + } + + @Test + public void testSwapPair() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(6); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(8); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + ListNode node = swapPairs(n1); + assertEquals("2 -> 1 -> 4 -> 3 -> 6 -> 5 -> 8 -> 7 -> 9", printList(node)); + } + + public ListNode swapPairsRec(ListNode A) { + // first swap two + // call swap with A.next.next + if (A == null || A.next == null) return A; + + ListNode temp = A.next.next; + + A.next.next = A; + ListNode head = A.next; + A.next = swapPairsRec(temp); + return head; + } + + @Test + public void testSwapPairRec() { + ListNode n1 = new ListNode(1); + ListNode n2 = new ListNode(2); + ListNode n3 = new ListNode(3); + ListNode n4 = new ListNode(4); + ListNode n5 = new ListNode(5); + ListNode n6 = new ListNode(6); + ListNode n7 = new ListNode(7); + ListNode n8 = new ListNode(8); + ListNode n9 = new ListNode(9); + n1.next = n2; + n2.next = n3; + n3.next = n4; + n4.next = n5; + n5.next = n6; + n6.next = n7; + n7.next = n8; + n8.next = n9; + ListNode node = swapPairsRec(n1); + assertEquals("2 -> 1 -> 4 -> 3 -> 6 -> 5 -> 8 -> 7 -> 9", printList(node)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/map/MyMap.java b/src/main/java/com/eprogrammerz/examples/ds/custom/map/MyMap.java index 414e128..edd2f2a 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/custom/map/MyMap.java +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/map/MyMap.java @@ -2,19 +2,37 @@ public class MyMap { private Entry[] buckets; - private static final int INITIAL_CAPACITY = 1 << 4; // 16 + private int capacity; // 16 private int size = 0; + private double lf = 0.75; + public MyMap() { - this(INITIAL_CAPACITY); + this(16); } public MyMap(int capacity) { - this.buckets = new Entry[capacity]; + this.capacity = capacity; + this.buckets = new Entry[this.capacity]; } public void put(K key, V value) { + if (size == lf * capacity) { + // rehash + Entry[] old = buckets; + + capacity *= 2; + size = 0; + buckets = new Entry[capacity]; + + for (Entry e: old) { + while (e != null) { + put(e.key, e.value); + e = e.next; + } + } + } Entry entry = new Entry<>(key, value, null); int bucket = getHash(key) % getBucketSize(); diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/map/Validator.java b/src/main/java/com/eprogrammerz/examples/ds/custom/map/Validator.java index 5776bdf..c56bae5 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/custom/map/Validator.java +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/map/Validator.java @@ -9,7 +9,7 @@ public class Validator { @Test public void testMyMap() { - MyMap myMap = new MyMap<>(); + MyMap myMap = new MyMap<>(3); myMap.put("USA", "Washington DC"); myMap.put("Nepal", "Kathmandu"); myMap.put("India", "New Delhi"); diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/queue/BlockingQueue.java b/src/main/java/com/eprogrammerz/examples/ds/custom/queue/BlockingQueue.java new file mode 100644 index 0000000..bd4c0b1 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/queue/BlockingQueue.java @@ -0,0 +1,59 @@ +package com.eprogrammerz.examples.ds.custom.queue; + +import java.util.LinkedList; +import java.util.Queue; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.ReentrantLock; + +/** + * https://leetcode.com/problems/design-bounded-blocking-queue/ + */ +public class BlockingQueue { + class BoundedBlockingQueue { + private Queue q; + private int capacity; + private ReentrantLock lock = new ReentrantLock(); + private Condition full = lock.newCondition(); + private Condition empty = lock.newCondition(); + + + public BoundedBlockingQueue(int capacity) { + this.capacity = capacity; + this.q = new LinkedList<>(); + } + + public void enqueue(int element) throws InterruptedException { + lock.lock(); + try { + while (q.size() >= capacity) full.await(); + + q.add(element); + + empty.signalAll(); + } finally { + if (lock.isLocked()) lock.unlock(); + } + } + + public int dequeue() throws InterruptedException { + lock.lock(); + int val; + try { + while (size() == 0) { + empty.await(); + } + + val = q.poll(); + + full.signalAll(); + } finally { + if (lock.isLocked()) lock.unlock(); + } + return val; + } + + public int size() { + return q.size(); + } + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/queue/CircularQueue.java b/src/main/java/com/eprogrammerz/examples/ds/custom/queue/CircularQueue.java new file mode 100644 index 0000000..5324627 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/queue/CircularQueue.java @@ -0,0 +1,116 @@ +package com.eprogrammerz.examples.ds.custom.queue; + +import org.junit.Test; + +import java.util.Arrays; + +import static org.junit.Assert.*; + +/** + * https://leetcode.com/problems/design-circular-queue/ + */ +public class CircularQueue { + class MyCircularQueue { + + private int[] arr; + private int head; + private int tail; + /** Initialize your data structure here. Set the size of the queue to be k. */ + public MyCircularQueue(int k) { + this.arr = new int[k]; + Arrays.fill(this.arr, -1); + } + + /** Insert an element into the circular queue. Return true if the operation is successful. */ + public boolean enQueue(int value) { + if (isFull()) return false; + + if (tail == arr.length - 1) { + tail = 0; + } + + if (tail == 0 && arr[tail] == -1) { + arr[0] = value; + return true; + } + + arr[++tail] = value; + + return true; + } + + /** Delete an element from the circular queue. Return true if the operation is successful. */ + public boolean deQueue() { + if (isEmpty()) return false; + arr[head] = -1; + if (head + 1 < arr.length && arr[head + 1] != -1) { + head++; + } + if (head == arr.length) head = 0; + return true; + } + + /** Get the front item from the queue. */ + public int Front() { + return isEmpty() ? -1 : arr[head]; + } + + /** Get the last item from the queue. */ + public int Rear() { + return isEmpty() ? -1 : arr[tail]; + } + + /** Checks whether the circular queue is empty or not. */ + public boolean isEmpty() { + return head == tail && arr[head] == -1; + } + + /** Checks whether the circular queue is full or not. */ + public boolean isFull() { + return (tail == arr.length - 1 && head == 0 && arr[tail] != -1 && arr[head] != -1) + || (tail + 1 == head && arr[tail] != -1 && arr[head] != -1); + } + } + + @Test + public void test1() { + MyCircularQueue queue = new MyCircularQueue(3); + assertTrue(queue.enQueue(1)); + assertTrue(queue.enQueue(2)); + assertTrue(queue.enQueue(3)); + assertFalse(queue.enQueue(4)); + assertEquals(3, queue.Rear()); + assertTrue(queue.isFull()); + assertTrue(queue.deQueue()); + assertTrue(queue.enQueue(5)); + assertEquals(5, queue.Rear()); + assertEquals(2, queue.Front()); + } + + @Test + public void test2() { + MyCircularQueue queue = new MyCircularQueue(6); + assertTrue(queue.enQueue(6)); + assertEquals(6, queue.Rear()); + assertTrue(queue.deQueue()); + assertTrue(queue.enQueue(4)); + assertEquals(4, queue.Rear()); + assertTrue(queue.deQueue()); + assertEquals(-1, queue.Front()); + assertFalse(queue.deQueue()); + assertFalse(queue.deQueue()); + assertFalse(queue.deQueue()); + } + + @Test + public void test3() { + MyCircularQueue queue = new MyCircularQueue(2); + assertTrue(queue.enQueue(4)); + assertTrue(queue.enQueue(9)); + assertTrue(queue.deQueue()); + assertTrue(queue.deQueue()); + + assertTrue(queue.enQueue(4)); + assertTrue(queue.enQueue(6)); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/set/MyHashSet.java b/src/main/java/com/eprogrammerz/examples/ds/custom/set/MyHashSet.java index 1b432e2..df1a717 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/custom/set/MyHashSet.java +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/set/MyHashSet.java @@ -30,7 +30,7 @@ */ public class MyHashSet { - private static final Integer INITIAL_CAPACITY = 1 << 4; // 16 + private int capacity = 0; private Node[] buckets; @@ -42,10 +42,22 @@ public MyHashSet(final int capacity) { } public MyHashSet() { - this(INITIAL_CAPACITY); + this(16); } public void add(T t) { + if (size == 0.75 * capacity) { + // rehash + capacity *= 2; + size = 0; + + for (Node bucket: buckets) { + while (bucket != null) { + add(bucket.data); + bucket = bucket.next; + } + } + } int index = hashCode(t) % buckets.length; Node bucket = buckets[index]; diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/set/Validator.java b/src/main/java/com/eprogrammerz/examples/ds/custom/set/Validator.java index cf6373a..7a59177 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/custom/set/Validator.java +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/set/Validator.java @@ -10,7 +10,7 @@ public class Validator { @Test public void testMyHashSet() { - MyHashSet set = new MyHashSet<>(); + MyHashSet set = new MyHashSet<>(3); set.add("USA"); set.add("Nepal"); diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/stack/DinnerPlates.java b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/DinnerPlates.java new file mode 100644 index 0000000..994e0bc --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/DinnerPlates.java @@ -0,0 +1,77 @@ +package com.eprogrammerz.examples.ds.custom.stack; + +import java.util.*; + +/** + * https://leetcode.com/problems/dinner-plate-stacks/ + */ +public class DinnerPlates { + + private List> l; + private PriorityQueue pq; + private int capacity; + private Set candidates; + + public DinnerPlates(int capacity) { + this.capacity = capacity; + this.l = new ArrayList<>(); + this.l.add(new Stack<>()); // add stack at 0 + this.pq = new PriorityQueue<>(); + this.pq.offer(0); // let pq know that stack at 0 is candidate stack + this.candidates = new HashSet<>(); + this.candidates.add(0); + } + + public void push(int val) { + int idx = pq.peek(); + Stack stack = l.get(idx); + stack.push(val); + + if (stack.size() == capacity) { + candidates.remove(idx); + pq.poll(); + + if (l.size() == idx + 1) { + l.add(new Stack<>()); + candidates.add(idx + 1); + pq.offer(idx + 1); + } + + } + } + + public int pop() { + int idx = l.size() - 1; + Stack stack = l.get(idx); + if (stack == null) return -1; + + if (stack.isEmpty()) { + if (idx == 0) return -1; + + l.remove(idx); + return pop(); + } + + int val = stack.pop(); + + if (candidates.add(idx)) { + pq.offer(idx); + } + return val; + } + + public int popAtStack(int index) { + if (index >= l.size()) return -1; // no stack at this index + Stack stack = l.get(index); + + if (stack == null || stack.isEmpty()) return -1; + + int val = stack.pop(); + + if (candidates.add(index)) { + pq.add(index); + } + + return val; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/stack/FreqStack.java b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/FreqStack.java new file mode 100644 index 0000000..6ff4f3b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/FreqStack.java @@ -0,0 +1,117 @@ +package com.eprogrammerz.examples.ds.custom.stack; + +import java.util.HashMap; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Stack; + +public class FreqStack { + private Map map; + private Map> timestamp; + private PriorityQueue pq; + private int count; + + public FreqStack() { + this.map = new HashMap<>(); + this.timestamp = new HashMap<>(); + this.pq = new PriorityQueue<>((e1, e2) -> map.get(e1).equals(map.get(e2)) ? + timestamp.get(e2).peek() - timestamp.get(e1).peek() : + map.get(e2) - map.get(e1)); + } + + public void push(int x) { + map.put(x, map.getOrDefault(x, 0) + 1); + timestamp.computeIfAbsent(x, s -> new Stack<>()).push(count++); + + if (map.get(x) == 1) { + pq.offer(x); + } else { + PriorityQueue temp = new PriorityQueue<>(); + while (!pq.isEmpty()) temp.add(pq.poll()); + + pq.addAll(temp); + } + } + + public int pop() { + int curr = pq.poll(); + + int count = map.get(curr) - 1; + + if (count == 0) { + map.remove(curr); + timestamp.remove(curr); + } else { + map.put(curr, count); + timestamp.get(curr).pop(); + pq.offer(curr); + } + return curr; + } + /* + private Node head; + private Map map; + + public FreqStack() { + this.map = new HashMap<>(); + } + + public void push(int x) { + Node node = new Node(x); + if (head == null) { + head = node; + } else { + node.next = head; + head = node; + } + + map.put(x, map.getOrDefault(x, 0) + 1); + + } + + public int pop() { + int freq = findFreq(); + if (map.get(head.val) == freq) { + int x = head.val; + head = head.next; + map.put(x, freq - 1); + return x; + } else { + Node prev = head; + Node node = head.next; + // search for requent element and update + while (node != null) { + if (map.get(node.val) == freq) { + prev.next = node.next; + map.put(node.val, freq - 1); + return node.val; + } + prev = node; + node = node.next; + } + } + return Integer.MIN_VALUE; + } + + private int findFreq() { + int top = Integer.MIN_VALUE; + for (int k: map.keySet()) { + int v = map.get(k); + if (v > top) { + top = v; + } + } + return top; + } + + static class Node { + int val; + Node next; + Node(int val) { + this.val = val; + this.next = null; + } + } + + */ +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/stack/StackWHeap.java b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/StackWHeap.java new file mode 100644 index 0000000..78a5382 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/StackWHeap.java @@ -0,0 +1,32 @@ +package com.eprogrammerz.examples.ds.custom.stack; + +import java.util.Comparator; +import java.util.EmptyStackException; +import java.util.PriorityQueue; + +public class StackWHeap { + private PriorityQueue pq; + public StackWHeap() { + this.pq = new PriorityQueue<>(Comparator.comparingInt(e -> e[1])); + } + + public void push(int n) { + // update all entry in pq with their count + PriorityQueue temp = new PriorityQueue<>(Comparator.comparingInt(e -> e[1])); + while (!pq.isEmpty()) { + int[] e = pq.poll(); + e[1]++; + temp.add(e); + } + pq.addAll(temp); + pq.add(new int[] {n, 1}); + } + + public int pop() { + if (pq.isEmpty()) { + throw new EmptyStackException(); + } + int[] e = pq.poll(); + return e[0]; + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/stack/StackWQueue.java b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/StackWQueue.java new file mode 100644 index 0000000..8958f4f --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/StackWQueue.java @@ -0,0 +1,54 @@ +package com.eprogrammerz.examples.ds.custom.stack; + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Implement the following operations of a stack using queues. + * + * push(x) -- Push element x onto stack. + * pop() -- Removes the element on top of the stack. + * top() -- Get the top element. + * empty() -- Return whether the stack is empty. + * Example: + * + * MyStack stack = new MyStack(); + * + * stack.push(1); + * stack.push(2); + * stack.top(); // returns 2 + * stack.pop(); // returns 2 + * stack.empty(); // returns false + */ +public class StackWQueue { + private Queue q1; + /** Initialize your data structure here. */ + public StackWQueue() { + this.q1 = new LinkedList<>(); + } + + /** Push element x onto stack. */ + // O(1) + public void push(int x) { + this.q1.add(x); + int size = q1.size(); + for (int i = 0; i < size - 1; i++) { + q1.add(q1.poll()); + } + } + + /** Removes the element on top of the stack and returns that element. */ + public int pop() { + return this.q1.poll(); + } + + /** Get the top element. */ + public int top() { + return this.q1.peek(); + } + + /** Returns whether the stack is empty. */ + public boolean empty() { + return q1.isEmpty(); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/stack/Validator.java b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/Validator.java index 271b60a..a3515c2 100644 --- a/src/main/java/com/eprogrammerz/examples/ds/custom/stack/Validator.java +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/stack/Validator.java @@ -70,4 +70,123 @@ public void testSortedStack() { assertEquals(4, sortedStack.pop()); assertEquals(5, sortedStack.pop()); } + + @Test + public void testStackWQueue() { + StackWQueue stack = new StackWQueue(); + stack.push(1); + stack.push(2); + stack.push(3); + assertEquals(3, stack.pop()); + assertEquals(2, stack.pop()); + stack.push(4); + assertEquals(4, stack.pop()); + assertEquals(1, stack.pop()); + } + + @Test + public void testFreqStack1() { + FreqStack stack = new FreqStack(); + stack.push(5); + stack.push(7); + stack.push(5); + stack.push(7); + stack.push(4); + stack.push(5); + assertEquals(5, stack.pop()); + assertEquals(7, stack.pop()); + assertEquals(5, stack.pop()); + assertEquals(4, stack.pop()); + } + + @Test + public void testFreqStack2() { + FreqStack stack = new FreqStack(); + stack.push(5); + stack.push(1); + stack.push(2); + stack.push(5); + stack.push(5); + stack.push(5); + stack.push(1); + stack.push(6); + stack.push(1); + stack.push(5); + assertEquals(5, stack.pop()); // 5 -> 5, 1 -> 3 + assertEquals(5, stack.pop()); // 5 -> 4, 1 -> 3 + assertEquals(1, stack.pop()); // 5 -> 3, 1 -> 3 + assertEquals(5, stack.pop()); // 5 -> 3, 1 -> 2 + assertEquals(1, stack.pop()); // 5 -> 2, 1 -> 2 + assertEquals(5, stack.pop()); // 5 -> 2, 1 -> 1 + assertEquals(6, stack.pop()); // 5 -> 1, 1 -> 1 + assertEquals(2, stack.pop()); // 5 -> 1, 1 -> 1 + assertEquals(1, stack.pop()); // 5 -> 1, 1 -> 1 + assertEquals(5, stack.pop()); // 5 -> 1, 1 -> 1 + } + + @Test + public void testStackWHeap() { + StackWHeap stack = new StackWHeap(); + stack.push(1); + stack.push(2); + stack.push(3); + stack.push(1); + + assertEquals(1, stack.pop()); + assertEquals(3, stack.pop()); + assertEquals(2, stack.pop()); + assertEquals(1, stack.pop()); + } + + @Test + public void testDinnerPlate1() { + DinnerPlates dinnerPlates = new DinnerPlates(2); + dinnerPlates.push(1); + dinnerPlates.push(2); + dinnerPlates.push(3); + dinnerPlates.push(4); + dinnerPlates.push(5); + + assertEquals(2, dinnerPlates.popAtStack(0)); + + dinnerPlates.push(20); + dinnerPlates.push(21); + + assertEquals(20, dinnerPlates.popAtStack(0)); + assertEquals(21, dinnerPlates.popAtStack(2)); + assertEquals(5, dinnerPlates.pop()); + assertEquals(4, dinnerPlates.pop()); + assertEquals(3, dinnerPlates.pop()); + assertEquals(1, dinnerPlates.pop()); + assertEquals(-1, dinnerPlates.pop()); + } + + @Test + public void testDinnerPlate2() { + DinnerPlates dinnerPlates = new DinnerPlates(2); + dinnerPlates.push(1); + dinnerPlates.push(2); + dinnerPlates.push(3); + dinnerPlates.push(4); + dinnerPlates.push(5); + dinnerPlates.push(6); + dinnerPlates.push(7); + + assertEquals(4, dinnerPlates.popAtStack(1)); + assertEquals(3, dinnerPlates.popAtStack(1)); + + + assertEquals(6, dinnerPlates.popAtStack(2)); + assertEquals(5, dinnerPlates.popAtStack(2)); + + + assertEquals(7, dinnerPlates.popAtStack(3)); + + dinnerPlates.push(12); + assertEquals(12, dinnerPlates.popAtStack(1)); + + assertEquals(2, dinnerPlates.pop()); + assertEquals(1, dinnerPlates.pop()); + assertEquals(-1, dinnerPlates.pop()); + } } diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MagicDictionaryTest.java b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MagicDictionaryTest.java new file mode 100644 index 0000000..756ee7b --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MagicDictionaryTest.java @@ -0,0 +1,100 @@ +package com.eprogrammerz.examples.ds.custom.trie; + +import org.junit.Test; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; + +public class MagicDictionaryTest { + @Test + public void test1() { + MagicDictionary dictionary = new MagicDictionary(); + dictionary.buildDict(new String[] {"hello", "leetcode"}); + + assertFalse(dictionary.search("hello")); + assertTrue(dictionary.search("hhllo")); + assertFalse(dictionary.search("hell")); + assertFalse(dictionary.search("leetcoded")); + } +} + +class MagicDictionary { + private Trie trie; + + /** Initialize your data structure here. */ + public MagicDictionary() { + this.trie = new Trie(); + } + + /** Build a dictionary through a list of words */ + public void buildDict(String[] dict) { + for (String str: dict) { + trie.insert(str); + } + } + + /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */ + public boolean search(String word) { + return trie.search(word); + } + + + class Trie { + TrieNode root; + Trie() { + this.root = new TrieNode(); + } + + void insert(String str) { + TrieNode curr = root; + + for (char ch: str.toCharArray()) { + if (curr.child[ch - 'a'] == null) { + curr.child[ch - 'a'] = new TrieNode(); + } + curr = curr.child[ch - 'a']; + } + curr.isWord = true; + } + + boolean search(String str) { + char[] arr = str.toCharArray(); + + for (int i = 0; i < arr.length; i++) { + for (char ch = 'a'; ch <= 'z'; ch++) { + if (ch == arr[i]) continue; + + char org = arr[i]; + arr[i] = ch; + + if (helper(new String(arr))) { + return true; + } + arr[i] = org; + } + } + return false; + } + + boolean helper(String str) { + TrieNode curr = root; + + for (char ch: str.toCharArray()) { + if (curr.child[ch - 'a'] == null) return false; + curr = curr.child[ch - 'a']; + } + return curr.isWord; + } + + + class TrieNode { + boolean isWord; + TrieNode[] child; + TrieNode() { + this.child = new TrieNode[26]; + } + } + } + + +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MapSumPairs.java b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MapSumPairs.java new file mode 100644 index 0000000..9c69c15 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MapSumPairs.java @@ -0,0 +1,156 @@ +package com.eprogrammerz.examples.ds.custom.trie; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; + + +/** + * https://leetcode.com/problems/map-sum-pairs/ + * + * + * Implement a MapSum class with insert, and sum methods. + * + * For the method insert, you'll be given a pair of (string, integer). + * The string represents the key and the integer represents the value. If the key already existed, then the original key-value pair + * will be overridden to the new one. + * + * For the method sum, you'll be given a string representing the prefix, + * and you need to return the sum of all the pairs' value whose key starts with the prefix. + * + * Example 1: + * Input: insert("apple", 3), Output: Null + * Input: sum("ap"), Output: 3 + * Input: insert("app", 2), Output: Null + * Input: sum("ap"), Output: 5 + */ +public class MapSumPairs { + @Test + public void test() { + MapSum mapSum = new MapSum(); + mapSum.insert("apple", 3); + assertEquals(3, mapSum.sum("ap")); + + mapSum.insert("app", 5); + assertEquals(8, mapSum.sum("ap")); + } +} + +class MapSum { + private Trie trie; + private Map m; + + /** + * Initialize your data structure here. + */ + public MapSum() { + this.m = new HashMap<>(); + this.trie = new Trie(); + } + + public void insert(String key, int val) { + if (!m.containsKey(key)) { + // put into trie + this.trie.insert(key); + } + m.put(key, val); + } + + public int sum(String prefix) { + List words = this.trie.search(prefix); + + int sum = 0; + + for (String word : words) { + sum += m.get(word); + } + + return sum; + } + + + class Trie { + TrieNode root; + + Trie() { + this.root = new TrieNode('#'); + } + + public void insert(String word) { + this.root.insert(word); + } + + public List search(String prefix) { + TrieNode node = this.root.search(prefix); + + List l = new ArrayList<>(); + if (node == null) return l; + + dfs(node, l, prefix.substring(0, prefix.length() - 1)); + return l; + } + + private void dfs(TrieNode node, List l, String word) { + if (node == null) return; + Map children = node.children; + if (children.containsKey('\0')) { + l.add(word + node.data); + } + + for (TrieNode child : children.values()) { + if (child != null && child.data != '\0') { + dfs(child, l, word + node.data); + } + } + } + } + + class TrieNode { + char data; + Map children; + + TrieNode(char data) { + this.data = data; + this.children = new HashMap<>(); + } + + public void insert(String word) { + if (word == null) return; + if (word.length() == 0) { + children.put('\0', null); + return; + } + char start = word.charAt(0); + TrieNode child = null; + if (children.containsKey(start)) { + child = children.get(start); + } else { + child = new TrieNode(start); + children.put(start, child); + } + child.insert(word.substring(1)); + } + + public TrieNode search(String prefix) { + + if (prefix.length() == 0) return null; + + char start = prefix.charAt(0); + TrieNode node = null; + if (children.containsKey(start)) { + + TrieNode child = children.get(start); + + if (prefix.length() == 1) return child; + node = child.search(prefix.substring(1)); + } + return node; + } + } +} + diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MaxDistanceTest.java b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MaxDistanceTest.java new file mode 100644 index 0000000..a81b75d --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/MaxDistanceTest.java @@ -0,0 +1,82 @@ +package com.eprogrammerz.examples.ds.custom.trie; + +import org.junit.Test; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +/** + * The distance between 2 binary strings is the sum of their lengths after removing the common prefix. + * For example: the common prefix of 1011000 and 1011110 is 1011 so the distance is len("000") + len("110") = 3 + 3 = 6. + * + * Given a list of binary strings, pick a pair that gives you maximum distance among all possible pair and return that distance. + */ +public class MaxDistanceTest { + @Test + public void test() { + assertEquals(6, maxDistance(new String[]{"1011000", "1011110"})); + assertEquals(9, maxDistance(new String[]{"1011000", "1011110", "1101"})); + assertEquals(9, maxDistance(new String[]{"1011000", "1011110", "1101", "01"})); + assertEquals(10, maxDistance(new String[]{"1011000", "1011110", "1101", "011"})); + } + + public int maxDistance(String[] strs) { + trie = new Trie(); + + for (String str : strs) { + trie.insert(str); + } + + return trie.search(); + } + + private Trie trie; + + private class Trie { + TrieNode root; + + Trie() { + this.root = new TrieNode(); + } + + public void insert(String word) { + TrieNode curr = root; + + for (char ch : word.toCharArray()) { + int val = (ch - '0'); + + if (curr.childs[val] == null) { + curr.childs[val] = new TrieNode(); + } + curr = curr.childs[val]; + } + } + + int max; + + public int search() { + Set visited = new HashSet<>(); + dfs(root, visited); + return max; + } + + private int dfs(TrieNode node, Set visited) { + if (node == null) return 0; + visited.add(node); + + int l = dfs(node.childs[0], visited); + int r = dfs(node.childs[1], visited); + + if (node.childs[0] != null && node.childs[1] != null) { + max = Math.max(max, l + r); + } + return Math.max(l, r) + 1; + } + } + + private class TrieNode { + TrieNode[] childs = new TrieNode[2]; + } +} \ No newline at end of file diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/trie/TrieExample.java b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/TrieExample.java new file mode 100644 index 0000000..f2fddeb --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/TrieExample.java @@ -0,0 +1,98 @@ +package com.eprogrammerz.examples.ds.custom.trie; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +public class TrieExample { + @Test + public void test() { + Trie trie = new Trie(); + trie.insert("apple"); + assertTrue(trie.search("apple")); + assertFalse(trie.search("app")); + assertTrue(trie.startsWith("app")); + + trie.insert("app"); + assertTrue(trie.search("app")); + + trie.insert("example"); + trie.insert("elephant"); + trie.insert("ex"); + + assertTrue(trie.search("example")); + assertTrue(trie.startsWith("ele")); + assertFalse(trie.startsWith("le")); + } +} + +class Trie { + private TrieNode root; + /** Initialize your data structure here. */ + public Trie() { + root = new TrieNode('#'); + } + + /** Inserts a word into the trie. */ + public void insert(String word) { + this.root.insert(word); + } + + /** Returns if the word is in the trie. */ + public boolean search(String word) { + return this.root.search(word); + } + + /** Returns if there is any word in the trie that starts with the given prefix. */ + public boolean startsWith(String prefix) { + return this.root.startsWith(prefix); + } +} + +class TrieNode { + private char data; + private Map children; + TrieNode(char data) { + this.data = data; + this.children = new HashMap<>(); + } + + public boolean startsWith(String word) { + if (word.isEmpty()) return true; + char ch = word.charAt(0); + TrieNode child = children.get(ch); + if (child == null) return false; + return child.startsWith(word.substring(1)); + } + + public boolean search(String word) { + if (word == null) return false; + if (word.isEmpty() && children.containsKey('\0')) return true; + if (word.isEmpty()) return false; + + char ch = word.charAt(0); + TrieNode child = children.get(ch); + if (child == null) return false; + return child.search(word.substring(1)); + } + + public void insert(String word) { + if (word != null && word.length() > 0) { + char ch = word.charAt(0); + TrieNode child = children.get(ch); + if (child == null) { + child = new TrieNode(ch); + children.put(ch, child); + } + + child.insert(word.substring(1)); + + } else { + children.put('\0', null); + } + } +} diff --git a/src/main/java/com/eprogrammerz/examples/ds/custom/trie/WordDictionaryTest.java b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/WordDictionaryTest.java new file mode 100644 index 0000000..9498723 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/ds/custom/trie/WordDictionaryTest.java @@ -0,0 +1,121 @@ +package com.eprogrammerz.examples.ds.custom.trie; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + +/** + * Design a data structure that supports the following two operations: + * + * void addWord(word) + * bool search(word) + * search(word) can search a literal word or a regular expression string containing only letters a-z or .. A . means it can represent any one letter. + * + * Example: + * + * addWord("bad") + * addWord("dad") + * addWord("mad") + * search("pad") -> false + * search("bad") -> true + * search(".ad") -> true + * search("b..") -> true + */ +public class WordDictionaryTest { + @Test + public void test1() { + WordDictionary dictionary = new WordDictionary(); + dictionary.addWord("a"); + dictionary.addWord("a"); + + assertTrue(dictionary.search(".")); + assertTrue(dictionary.search("a")); + assertFalse(dictionary.search("aa")); + assertTrue(dictionary.search("a")); + assertFalse(dictionary.search("a.")); + assertFalse(dictionary.search(".a")); + + dictionary.addWord("add"); + assertTrue(dictionary.search("a.d")); + } + + @Test + public void test2() { + WordDictionary dictionary = new WordDictionary(); + dictionary.addWord("at"); + dictionary.addWord("and"); + dictionary.addWord("an"); + dictionary.addWord("add"); + assertFalse(dictionary.search(".at")); + dictionary.addWord("bat"); + assertTrue(dictionary.search(".at")); + } +} + +class WordDictionary { + + private Node root; + /** Initialize your data structure here. */ + public WordDictionary() { + this.root = new Node('#'); + } + + /** Adds a word into the data structure. */ + public void addWord(String word) { + root.addWord(word); + } + + /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */ + public boolean search(String word) { + return root.search(word); + } +} + +class Node { + char data; + Map children; + Node(char data) { + this.data = data; + this.children = new HashMap<>(); + } + + void addWord(String word) { + if (word == null) return; + + if (word.isEmpty()) { + children.put('\0', null); + return; + } + + char ch = word.charAt(0); + Node child = children.get(ch); + if (child == null) { + child = new Node(ch); + children.put(ch, child); + } + child.addWord(word.substring(1)); + } + + boolean search(String word) { + if (word == null) return false; + if (word.isEmpty() && children.containsKey('\0')) return true; + if (word.isEmpty()) return false; + char ch = word.charAt(0); + if (ch == '.') { + boolean has = false; + for (Node node: children.values()) { + if (node != null) { + has = has || node.search(word.substring(1)); + } + } + return has; + } + Node child = children.get(ch); + if (child == null) return false; + return child.search(word.substring(1)); + } +} \ No newline at end of file diff --git a/src/main/java/com/eprogrammerz/examples/threading/concurrency/FinishUpAllThread.java b/src/main/java/com/eprogrammerz/examples/threading/concurrency/FinishUpAllThread.java new file mode 100644 index 0000000..118a866 --- /dev/null +++ b/src/main/java/com/eprogrammerz/examples/threading/concurrency/FinishUpAllThread.java @@ -0,0 +1,62 @@ +package com.eprogrammerz.examples.threading.concurrency; + +import java.util.concurrent.*; + +public class FinishUpAllThread { + public static void testExecutorService() throws InterruptedException { + ExecutorService es = Executors.newFixedThreadPool(10); + + for (int i = 0; i < 5; i++) { + es.execute(new Thread(() -> { + try { + Thread.sleep(15000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Thread -> " + Thread.currentThread().getName()); + })); + } + + es.awaitTermination(10, TimeUnit.SECONDS); + + System.out.println("Done executing all threads . . ."); + if (!es.isShutdown()) { + System.out.println("Shutting down executor . . ."); + es.shutdown(); // graceful shutdown of the service + } + } + + public static void main(String[] args) throws InterruptedException { +// testExecutorService(); + testWithJoin(); + } + + public static void testWithJoin() throws InterruptedException { + Runnable r = () -> { + try { + Thread.sleep(15000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + System.out.println("Thread -> " + Thread.currentThread().getName()); + }; + + Thread t1 = new Thread(r); + Thread t2 = new Thread(r); + Thread t3 = new Thread(r); + Thread t4 = new Thread(r); + + t1.start(); + t2.start(); + t3.start(); + t4.start(); + + // join all threads to the main thread i.e. before joining t2 to main thread, t1 should + // have been joined + t1.join(); + t2.join(); + t3.join(); + t4.join(); + System.out.println("Done with all threads!"); + } +} diff --git a/src/main/java/com/eprogrammerz/examples/threading/MultiThreadWExecutor.java b/src/main/java/com/eprogrammerz/examples/threading/concurrency/MultiThreadWExecutor.java similarity index 96% rename from src/main/java/com/eprogrammerz/examples/threading/MultiThreadWExecutor.java rename to src/main/java/com/eprogrammerz/examples/threading/concurrency/MultiThreadWExecutor.java index 1398f74..f240e54 100644 --- a/src/main/java/com/eprogrammerz/examples/threading/MultiThreadWExecutor.java +++ b/src/main/java/com/eprogrammerz/examples/threading/concurrency/MultiThreadWExecutor.java @@ -1,4 +1,4 @@ -package com.eprogrammerz.examples.threading; +package com.eprogrammerz.examples.threading.concurrency; import org.junit.Test; diff --git a/src/main/resources/zoo_en.properties b/src/main/resources/zoo_en.properties new file mode 100644 index 0000000..0db7b0b --- /dev/null +++ b/src/main/resources/zoo_en.properties @@ -0,0 +1,2 @@ +hello=Hello +open=The Zoo is Open \ No newline at end of file diff --git a/src/main/resources/zoo_fr.properties b/src/main/resources/zoo_fr.properties new file mode 100644 index 0000000..cd347a5 --- /dev/null +++ b/src/main/resources/zoo_fr.properties @@ -0,0 +1,2 @@ +hello=Bonjour +open=Le zoo est ouvert \ No newline at end of file