From 4a0c4809102e9eef2d23d2bb8bd91fc492bc579b Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 23 May 2019 22:17:17 +0100 Subject: [PATCH 01/70] Minor fix --- src/main/java/com/rampatra/strings/WithoutString.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rampatra/strings/WithoutString.java b/src/main/java/com/rampatra/strings/WithoutString.java index 3269d093..859b6a76 100644 --- a/src/main/java/com/rampatra/strings/WithoutString.java +++ b/src/main/java/com/rampatra/strings/WithoutString.java @@ -39,7 +39,7 @@ private static String withoutString(String base, String remove) { public static void main(String[] args) { Assert.check(withoutString("Hello there", "llo").equals("He there")); - Assert.check(withoutString("THIS is a FISH", "is").equals("TH a FH")); + Assert.check(withoutString("THIS is a FISH", "is").equals("TH a FH")); Assert.check(withoutString("xxx", "x").equals("")); } } From 62efe961d9afd22c6942574e9b0d06d86bb41012 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 24 May 2019 19:51:17 +0100 Subject: [PATCH 02/70] Minor indentation fixed --- src/main/java/com/ctci/stacksandqueues/StackMin.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/ctci/stacksandqueues/StackMin.java b/src/main/java/com/ctci/stacksandqueues/StackMin.java index 780ecc9e..0a5d2d59 100644 --- a/src/main/java/com/ctci/stacksandqueues/StackMin.java +++ b/src/main/java/com/ctci/stacksandqueues/StackMin.java @@ -58,6 +58,5 @@ public static void main(String[] args) { Assert.check(min() == 1); pop(); Assert.check(min() == 2); - } -} +} \ No newline at end of file From 94bfb85d6d805a3cfc3ab48cd46d31caa51bea06 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 24 May 2019 19:59:22 +0100 Subject: [PATCH 03/70] Minor refactorings --- .../java/com/rampatra/misc/RandomTest.java | 7 ++--- ...aceAll.java => RegexReplaceAllSpaces.java} | 5 +-- .../{Regex.java => RegexValidateLatLong.java} | 5 +-- src/main/java/com/rampatra/misc/SPOJ1.java | 31 ------------------- 4 files changed, 4 insertions(+), 44 deletions(-) rename src/main/java/com/rampatra/misc/{ReplaceAll.java => RegexReplaceAllSpaces.java} (81%) rename src/main/java/com/rampatra/misc/{Regex.java => RegexValidateLatLong.java} (93%) delete mode 100644 src/main/java/com/rampatra/misc/SPOJ1.java diff --git a/src/main/java/com/rampatra/misc/RandomTest.java b/src/main/java/com/rampatra/misc/RandomTest.java index 9ff2a683..5c9590cc 100644 --- a/src/main/java/com/rampatra/misc/RandomTest.java +++ b/src/main/java/com/rampatra/misc/RandomTest.java @@ -3,11 +3,8 @@ import java.util.Random; /** - * Created by IntelliJ IDEA. - * User: rampatra - * Date: 2/23/15 - * Time: 12:48 PM - * To change this template go to Preferences | IDE Settings | File and Code Templates + * @author rampatra + * @since 2/23/15 */ public class RandomTest { public static void main(String[] args) { diff --git a/src/main/java/com/rampatra/misc/ReplaceAll.java b/src/main/java/com/rampatra/misc/RegexReplaceAllSpaces.java similarity index 81% rename from src/main/java/com/rampatra/misc/ReplaceAll.java rename to src/main/java/com/rampatra/misc/RegexReplaceAllSpaces.java index cc17b70f..04b33db6 100644 --- a/src/main/java/com/rampatra/misc/ReplaceAll.java +++ b/src/main/java/com/rampatra/misc/RegexReplaceAllSpaces.java @@ -1,13 +1,10 @@ package com.rampatra.misc; /** - * Created by IntelliJ IDEA. - * * @author rampatra * @since 11/3/15 - * @time: 2:21 PM */ -public class ReplaceAll { +public class RegexReplaceAllSpaces { public static String replaceAll(String str, String regex, String replacement) { return str.replaceAll(regex, replacement); diff --git a/src/main/java/com/rampatra/misc/Regex.java b/src/main/java/com/rampatra/misc/RegexValidateLatLong.java similarity index 93% rename from src/main/java/com/rampatra/misc/Regex.java rename to src/main/java/com/rampatra/misc/RegexValidateLatLong.java index 19fcdf11..e8d8d2d6 100644 --- a/src/main/java/com/rampatra/misc/Regex.java +++ b/src/main/java/com/rampatra/misc/RegexValidateLatLong.java @@ -5,13 +5,10 @@ import java.util.regex.Pattern; /** - * Created by IntelliJ IDEA. - * * @author rampatra * @since 9/12/15 - * @time: 1:49 PM */ -public class Regex { +public class RegexValidateLatLong { /** * Validates latitude/longitude in the form (+75, 180) etc. diff --git a/src/main/java/com/rampatra/misc/SPOJ1.java b/src/main/java/com/rampatra/misc/SPOJ1.java deleted file mode 100644 index fc1ad7a4..00000000 --- a/src/main/java/com/rampatra/misc/SPOJ1.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.rampatra.misc; - -import java.util.ArrayList; -import java.util.List; -import java.util.Scanner; - -/** - * Created by IntelliJ IDEA. - * User: rampatra - * Date: 4/22/15 - * Time: 7:40 PM - * To change this template go to Preferences | IDE Settings | File and Code Templates - */ -class SPOJ1 { - - public static void main(String[] args) { - Scanner in = new Scanner(System.in); - - List inputList = new ArrayList<>(); - int input; - for (; ; ) { - input = Integer.parseInt(in.nextLine()); - if (input == 42) break; - inputList.add(input); - } - - for (long i : inputList) { - System.out.println(i); - } - } -} From cde6e836f02b1b456d24e18f24846e5c7464c8d2 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 31 May 2019 11:54:54 +0100 Subject: [PATCH 04/70] FlattenArray done --- .../com/rampatra/arrays/FlattenArray.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/java/com/rampatra/arrays/FlattenArray.java diff --git a/src/main/java/com/rampatra/arrays/FlattenArray.java b/src/main/java/com/rampatra/arrays/FlattenArray.java new file mode 100644 index 00000000..e68c250b --- /dev/null +++ b/src/main/java/com/rampatra/arrays/FlattenArray.java @@ -0,0 +1,39 @@ +package com.rampatra.arrays; + +import java.util.ArrayList; +import java.util.List; + +public class FlattenArray { + + /** + * Given a nested array like [[1, 2], 3, [4]], return an array like [1, 2, 3, 4, 5]. + * + * @param nestedArray an Object array + * @return a list of all elements in the nestedArray but all at the same level + */ + private static List flattenArray(Object[] nestedArray) { + if (nestedArray == null || nestedArray.length == 0) return new ArrayList<>(); + + List flattenedArray = new ArrayList<>(); + + for (Object obj : nestedArray) { + if (obj instanceof Object[]) { + flattenedArray.addAll(flattenArray((Object[]) obj)); + } else if (obj instanceof Integer) { + flattenedArray.add((Integer) obj); + } + } + + return flattenedArray; + } + + public static void main(String[] args) { + System.out.println(flattenArray(null)); + System.out.println(flattenArray(new Object[]{null})); + System.out.println(flattenArray(new Object[]{new Object[]{}})); + System.out.println(flattenArray(new Object[]{new Object[]{1, 2}})); + System.out.println(flattenArray(new Object[]{1, 2, new Object[]{4, 5}, 6})); + System.out.println(flattenArray(new Object[]{new Object[]{4, 5}, 1, 2, 6})); + System.out.println(flattenArray(new Object[]{1, 2, 6, new Object[]{4, 5}})); + } +} \ No newline at end of file From 270ed1b7c8bd0327bd53f5bb44816c6b20b38df7 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 31 May 2019 21:17:42 +0100 Subject: [PATCH 05/70] ReverseInteger done --- .../com/leetcode/math/ReverseInteger.java | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 src/main/java/com/leetcode/math/ReverseInteger.java diff --git a/src/main/java/com/leetcode/math/ReverseInteger.java b/src/main/java/com/leetcode/math/ReverseInteger.java new file mode 100644 index 00000000..7e540778 --- /dev/null +++ b/src/main/java/com/leetcode/math/ReverseInteger.java @@ -0,0 +1,62 @@ +package com.leetcode.math; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/reverse-integer/ + * Problem Description: + * Given a 32-bit signed integer, reverse digits of an integer. + *

+ * Example 1: + * Input: 123 + * Output: 321 + *

+ * Example 2: + * Input: -123 + * Output: -321 + *

+ * Example 3: + * Input: 120 + * Output: 21 + *

+ * Note: Assume we are dealing with an environment which could only store integers within the 32-bit signed + * integer range: [−2^31, 2^31 − 1]. For the purpose of this problem, assume that your function returns 0 when + * the reversed integer overflows. + * + * @author rampatra + * @since 2019-05-31 + */ +public class ReverseInteger { + + /** + * Reverses the input integer. + * Time complexity: O(d) + * where, + * d = number of digits in num + *

+ * Runtime: 1 ms. + * + * @param num an integer. + * @return the reverse of {@code num}. + */ + private static int reverse(int num) { + long reverse = 0; + int pop; + + while (num != 0) { + pop = num % 10; + num = num / 10; + reverse = reverse * 10 + pop; + } + + return reverse < Integer.MIN_VALUE || reverse > Integer.MAX_VALUE ? 0 : (int) reverse; + } + + public static void main(String[] args) { + System.out.println(reverse(0)); + System.out.println(reverse(-0)); + System.out.println(reverse(123)); + System.out.println(reverse(-123)); + System.out.println(reverse(Integer.MAX_VALUE)); + System.out.println(reverse(Integer.MIN_VALUE)); + } +} \ No newline at end of file From 43b4bd740ad7adfd7002e78243abd2d390c3de86 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 3 Jun 2019 20:25:40 +0100 Subject: [PATCH 06/70] Distinct pairs done --- .../leetcode/math/ExcelSheetColumnNumber.java | 44 ++++++++++++++++ .../com/rampatra/arrays/DistinctPairs.java | 50 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 src/main/java/com/leetcode/math/ExcelSheetColumnNumber.java create mode 100644 src/main/java/com/rampatra/arrays/DistinctPairs.java diff --git a/src/main/java/com/leetcode/math/ExcelSheetColumnNumber.java b/src/main/java/com/leetcode/math/ExcelSheetColumnNumber.java new file mode 100644 index 00000000..29e1dded --- /dev/null +++ b/src/main/java/com/leetcode/math/ExcelSheetColumnNumber.java @@ -0,0 +1,44 @@ +package com.leetcode.math; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/excel-sheet-column-number/ + * Problem Description: + * Given a column title as appear in an Excel sheet, return its corresponding column number. + * + * For example: + * + * A -> 1 + * B -> 2 + * C -> 3 + * ... + * Z -> 26 + * AA -> 27 + * AB -> 28 + * ... + * + * Example 1: + * Input: "A" + * Output: 1 + * + * Example 2: + * Input: "AB" + * Output: 28 + * + * Example 3: + * Input: "ZY" + * Output: 701 + * + * @author rampatra + * @since 2019-05-31 + */ +public class ExcelSheetColumnNumber { + + private static int titleToNumber(String title) { + return 0; + } + + public static void main(String[] args) { + + } +} diff --git a/src/main/java/com/rampatra/arrays/DistinctPairs.java b/src/main/java/com/rampatra/arrays/DistinctPairs.java new file mode 100644 index 00000000..3ba861ab --- /dev/null +++ b/src/main/java/com/rampatra/arrays/DistinctPairs.java @@ -0,0 +1,50 @@ +package com.rampatra.arrays; + +import java.util.HashSet; +import java.util.Set; + +/** + * Level: Easy + * Problem Description: + * Given an array and a target sum, return the number of distinct pairs whose sum is equal to the target sum. + *

+ * For Example, given an array [1, 2, 3, 6, 7, 8, 9, 1] and a target sum of 10, + * the 7 pairs, i.e, (1, 9), (2, 8), (3, 7), (8, 2), (9, 1), (9, 1), and (1, 9) all sum to 10 but there are only + * three distinct pairs, i.e, (1, 9), (2, 8), and (3, 7) so the answer would be 3. + * + * @author rampatra + * @since 2019-06-03 + */ +public class DistinctPairs { + + /** + * Time complexity: O(n), n = size of the array + * Space complexity: O(n) + * + * @param arr + * @param targetSum + * @return + */ + private static int numberOfDistinctPairs(int[] arr, int targetSum) { + Set numSet = new HashSet<>(); + Set> pairSet = new HashSet<>(); + + for (int i = 0; i < arr.length; i++) { + if (numSet.contains(targetSum - arr[i])) { + Set pair = new HashSet<>(); + pair.add(arr[i]); + pair.add(targetSum - arr[i]); + pairSet.add(pair); + } + numSet.add(arr[i]); + } + + return pairSet.size(); + } + + public static void main(String[] args) { + System.out.println(numberOfDistinctPairs(new int[]{1, 2, 3, 6, 7, 8, 9, 1}, 1)); + System.out.println(numberOfDistinctPairs(new int[]{1, 2, 3, 6, 7, 8, 9, 1}, 2)); + System.out.println(numberOfDistinctPairs(new int[]{1, 2, 3, 6, 7, 8, 9, 1}, 10)); + } +} \ No newline at end of file From 51d8742fac616ba0746ee5ba21324a96708be0da Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 3 Jun 2019 23:04:41 +0100 Subject: [PATCH 07/70] Read file in Java: done --- src/main/java/com/rampatra/misc/ReadFile.java | 71 +++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 src/main/java/com/rampatra/misc/ReadFile.java diff --git a/src/main/java/com/rampatra/misc/ReadFile.java b/src/main/java/com/rampatra/misc/ReadFile.java new file mode 100644 index 00000000..c5c64540 --- /dev/null +++ b/src/main/java/com/rampatra/misc/ReadFile.java @@ -0,0 +1,71 @@ +package com.rampatra.misc; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + +/** + * Various ways to read a file in Java. + * + * @author rampatra + * @since 2019-06-03 + */ +public class ReadFile { + + private static Stream readFile(String filePath) throws IOException { + return Files.lines(Paths.get(filePath)); // use Files.readAllLines() to return a List instead of Stream + } + + private static String readFile(Path filePath) throws IOException { + Stream lines = Files.lines(filePath); + String data = lines.collect(Collectors.joining("\n")); + lines.close(); + return data; + } + + private static List readLargeFile(Path filePath) throws IOException { + try (BufferedReader reader = Files.newBufferedReader(filePath)) { + List result = new ArrayList<>(); + for (; ; ) { + String line = reader.readLine(); + if (line == null) + break; + result.add(line); + } + return result; + } + } + + private static String readFileOldWay(String filePath) throws IOException { + try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) { + StringBuilder builder = new StringBuilder(); + String currentLine = reader.readLine(); + while (currentLine != null) { + builder.append(currentLine); + builder.append("\n"); + currentLine = reader.readLine(); + } + // reader.close(); not required as try-with-resources is used + + return builder.toString(); + } + } + + public static void main(String[] args) throws IOException { + readFile("src/main/java/com/rampatra/misc/reverseandadd.txt").forEach(System.out::println); + System.out.println("=================="); + System.out.println(readFile(Paths.get("src/main/java/com/rampatra/misc/reverseandadd.txt"))); + System.out.println("=================="); + System.out.println(readLargeFile(Paths.get("src/main/java/com/rampatra/misc/reverseandadd.txt"))); + System.out.println("=================="); + System.out.println(readFileOldWay("src/main/java/com/rampatra/misc/reverseandadd.txt")); + } +} From c5071d709d34d1468c02f22d4f64e7b834d72cd6 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 19 Jun 2019 16:50:31 +0100 Subject: [PATCH 08/70] Add one to linked list: done --- .../ctci/linkedlists/DeleteMiddleNode.java | 18 ++-- .../com/ctci/linkedlists/Intersection.java | 14 ++- .../ctci/linkedlists/KthToLastElement.java | 8 +- src/main/java/com/ctci/linkedlists/Node.java | 6 +- .../java/com/ctci/linkedlists/Palindrome.java | 10 +- .../java/com/ctci/linkedlists/Partition.java | 22 ++--- .../ctci/linkedlists/RemoveDuplicates.java | 24 +++-- .../java/com/ctci/linkedlists/SumLists.java | 20 ++-- .../linkedlists/AddOneToNumberInList.java | 91 +++++++++++++++++++ .../java/com/leetcode/linkedlists/Node.java | 23 +++++ 10 files changed, 167 insertions(+), 69 deletions(-) create mode 100644 src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java create mode 100644 src/main/java/com/leetcode/linkedlists/Node.java diff --git a/src/main/java/com/ctci/linkedlists/DeleteMiddleNode.java b/src/main/java/com/ctci/linkedlists/DeleteMiddleNode.java index 469690c7..c4b4052e 100644 --- a/src/main/java/com/ctci/linkedlists/DeleteMiddleNode.java +++ b/src/main/java/com/ctci/linkedlists/DeleteMiddleNode.java @@ -1,7 +1,5 @@ package com.ctci.linkedlists; -import static com.ctci.linkedlists.Node.printList; - /** * @author rampatra * @since 2019-01-27 @@ -35,33 +33,33 @@ public static void main(String[] args) { l1.next.next.next = new Node(4); l1.next.next.next.next = new Node(5); l1.next.next.next.next.next = new Node(6); - printList(l1); + l1.print(); deleteMiddleNode(l1.next.next); - printList(l1); + l1.print(); System.out.println("----"); l1 = new Node(1); l1.next = new Node(2); l1.next.next = new Node(3); - printList(l1); + l1.print(); deleteMiddleNode(l1.next); - printList(l1); + l1.print(); System.out.println("----"); l1 = new Node(1); l1.next = new Node(3); - printList(l1); + l1.print(); deleteMiddleNode(l1); - printList(l1); + l1.print(); System.out.println("----"); l1 = new Node(1); l1.next = new Node(3); - printList(l1); + l1.print(); deleteMiddleNode(l1.next); - printList(l1); + l1.print(); } } diff --git a/src/main/java/com/ctci/linkedlists/Intersection.java b/src/main/java/com/ctci/linkedlists/Intersection.java index c9d11b72..4665fe43 100644 --- a/src/main/java/com/ctci/linkedlists/Intersection.java +++ b/src/main/java/com/ctci/linkedlists/Intersection.java @@ -1,7 +1,5 @@ package com.ctci.linkedlists; -import static com.ctci.linkedlists.Node.printList; - /** * @author rampatra * @since 2019-02-02 @@ -75,16 +73,16 @@ public static void main(String[] args) { l2.next.next = new Node(2); l2.next.next.next = new Node(3); l2.next.next.next.next = l1.next.next.next; - printList(l1); - printList(l2); + l1.print(); + l2.print(); System.out.println(findIntersectingNode(l1, l2).val); // may throw NPE, not handling for the sake of simplicity System.out.println("----"); l1 = new Node(1); l2 = l1; - printList(l1); - printList(l2); + l1.print(); + l2.print(); System.out.println(findIntersectingNode(l1, l2).val); // may throw NPE, not handling for the sake of simplicity System.out.println("----"); @@ -99,8 +97,8 @@ public static void main(String[] args) { l2.next = new Node(4); l2.next.next = new Node(2); l2.next.next.next = new Node(3); - printList(l1); - printList(l2); + l1.print(); + l2.print(); System.out.println(findIntersectingNode(l1, l2)); } } diff --git a/src/main/java/com/ctci/linkedlists/KthToLastElement.java b/src/main/java/com/ctci/linkedlists/KthToLastElement.java index 9758d2f7..8fff3f9d 100644 --- a/src/main/java/com/ctci/linkedlists/KthToLastElement.java +++ b/src/main/java/com/ctci/linkedlists/KthToLastElement.java @@ -1,7 +1,5 @@ package com.ctci.linkedlists; -import static com.ctci.linkedlists.Node.printList; - /** * @author rampatra * @since 21/11/2018 @@ -60,7 +58,7 @@ public static void main(String[] args) { l1.next.next.next = new Node(4); l1.next.next.next.next = new Node(5); l1.next.next.next.next.next = new Node(7); - printList(l1); + l1.print(); System.out.println("k=2: " + getKthToLastElement(l1, 2).val); // NPE check is omitted intentionally to keep it simple System.out.print("k=2: "); printKthToLastElement(l1, 2); @@ -71,7 +69,7 @@ public static void main(String[] args) { l2.next.next.next = new Node(3); l2.next.next.next.next = new Node(4); l2.next.next.next.next.next = new Node(7); - printList(l2); + l2.print(); System.out.println("k=1: " + getKthToLastElement(l2, 1).val); System.out.print("k=1: "); printKthToLastElement(l2, 1); @@ -82,7 +80,7 @@ public static void main(String[] args) { l3.next.next.next = new Node(3); l3.next.next.next.next = new Node(4); l3.next.next.next.next.next = new Node(7); - printList(l3); + l3.print(); System.out.println("k=6: " + getKthToLastElement(l3, 6).val); System.out.print("k=6: "); printKthToLastElement(l3, 6); diff --git a/src/main/java/com/ctci/linkedlists/Node.java b/src/main/java/com/ctci/linkedlists/Node.java index a0f68cb1..5c0d1ec3 100644 --- a/src/main/java/com/ctci/linkedlists/Node.java +++ b/src/main/java/com/ctci/linkedlists/Node.java @@ -12,10 +12,8 @@ class Node { this.val = val; } - public static void printList(Node head) { - if (head == null) return; - - Node curr = head; + public void print() { + Node curr = this; while (curr.next != null) { System.out.print(curr.val + "->"); curr = curr.next; diff --git a/src/main/java/com/ctci/linkedlists/Palindrome.java b/src/main/java/com/ctci/linkedlists/Palindrome.java index 717a478e..57bb184d 100644 --- a/src/main/java/com/ctci/linkedlists/Palindrome.java +++ b/src/main/java/com/ctci/linkedlists/Palindrome.java @@ -2,8 +2,6 @@ import java.util.Stack; -import static com.ctci.linkedlists.Node.printList; - /** * @author rampatra * @since 2019-02-02 @@ -75,7 +73,7 @@ public static void main(String[] args) { l1.next.next.next = new Node(3); l1.next.next.next.next = new Node(2); l1.next.next.next.next.next = new Node(1); - printList(l1); + l1.print(); System.out.println(isPalindrome(l1)); System.out.println(isPalindromeOptimized(l1)); System.out.println("------"); @@ -85,7 +83,7 @@ public static void main(String[] args) { l1.next.next = new Node(3); l1.next.next.next = new Node(2); l1.next.next.next.next = new Node(1); - printList(l1); + l1.print(); System.out.println(isPalindrome(l1)); System.out.println(isPalindromeOptimized(l1)); System.out.println("------"); @@ -95,13 +93,13 @@ public static void main(String[] args) { l1.next.next = new Node(3); l1.next.next.next = new Node(3); l1.next.next.next.next = new Node(0); - printList(l1); + l1.print(); System.out.println(isPalindrome(l1)); System.out.println(isPalindromeOptimized(l1)); System.out.println("------"); l1 = new Node(1); - printList(l1); + l1.print(); System.out.println(isPalindrome(l1)); System.out.println(isPalindromeOptimized(l1)); diff --git a/src/main/java/com/ctci/linkedlists/Partition.java b/src/main/java/com/ctci/linkedlists/Partition.java index 406be3e5..8876a424 100644 --- a/src/main/java/com/ctci/linkedlists/Partition.java +++ b/src/main/java/com/ctci/linkedlists/Partition.java @@ -1,7 +1,5 @@ package com.ctci.linkedlists; -import static com.ctci.linkedlists.Node.printList; - /** * Write code to partition a linked list around a value x, such that all nodes less than x come before all * nodes greater than or equal to x. If x is contained within the list, the values of x only need to be @@ -59,36 +57,36 @@ public static void main(String[] args) { l1.next.next.next.next = new Node(10); l1.next.next.next.next.next = new Node(2); l1.next.next.next.next.next.next = new Node(1); - printList(l1); - printList(partition(l1, 5)); + l1.print(); + l1.print(); System.out.println("----"); l1 = new Node(1); l1.next = new Node(2); l1.next.next = new Node(3); - printList(l1); - printList(partition(l1, 2)); + l1.print(); + l1.print(); System.out.println("----"); l1 = new Node(3); l1.next = new Node(2); l1.next.next = new Node(1); - printList(l1); - printList(partition(l1, 2)); + l1.print(); + l1.print(); System.out.println("----"); l1 = new Node(1); - printList(l1); - printList(partition(l1, 1)); + l1.print(); + l1.print(); System.out.println("----"); l1 = null; - printList(l1); - printList(partition(l1, 1)); + l1.print(); + l1.print(); System.out.println("----"); } diff --git a/src/main/java/com/ctci/linkedlists/RemoveDuplicates.java b/src/main/java/com/ctci/linkedlists/RemoveDuplicates.java index df65cf06..31029188 100644 --- a/src/main/java/com/ctci/linkedlists/RemoveDuplicates.java +++ b/src/main/java/com/ctci/linkedlists/RemoveDuplicates.java @@ -3,8 +3,6 @@ import java.util.HashSet; import java.util.Set; -import static com.ctci.linkedlists.Node.printList; - /** * @author rampatra * @since 21/11/2018 @@ -44,10 +42,10 @@ public static void main(String[] args) { l1.next.next.next.next = new Node(5); l1.next.next.next.next.next = new Node(5); System.out.print("With dups: "); - printList(l1); + l1.print(); removeDuplicatesFromUnsortedList(l1); System.out.print("Without dups: "); - printList(l1); + l1.print(); Node l2 = new Node(1); l2.next = new Node(1); @@ -56,10 +54,10 @@ public static void main(String[] args) { l2.next.next.next.next = new Node(4); l2.next.next.next.next.next = new Node(5); System.out.print("\nWith dups: "); - printList(l2); + l2.print(); removeDuplicatesFromUnsortedList(l2); System.out.print("Without dups: "); - printList(l2); + l2.print(); Node l3 = new Node(1); l3.next = new Node(2); @@ -68,23 +66,23 @@ public static void main(String[] args) { l3.next.next.next.next = new Node(4); l3.next.next.next.next.next = new Node(5); System.out.print("\nWith dups: "); - printList(l3); + l3.print(); removeDuplicatesFromUnsortedList(l3); System.out.print("Without dups: "); - printList(l3); - + l3.print(); + Node l4 = new Node(1); System.out.print("\nWith dups: "); - printList(l4); + l4.print(); removeDuplicatesFromUnsortedList(l4); System.out.print("Without dups: "); - printList(l4); + l4.print(); Node l5 = null; System.out.print("\nWith dups: "); - printList(l5); + l5.print(); removeDuplicatesFromUnsortedList(l5); System.out.print("Without dups: "); - printList(l5); + l5.print(); } } \ No newline at end of file diff --git a/src/main/java/com/ctci/linkedlists/SumLists.java b/src/main/java/com/ctci/linkedlists/SumLists.java index e3ebc677..befdfc3e 100644 --- a/src/main/java/com/ctci/linkedlists/SumLists.java +++ b/src/main/java/com/ctci/linkedlists/SumLists.java @@ -1,7 +1,5 @@ package com.ctci.linkedlists; -import static com.ctci.linkedlists.Node.printList; - /** * @author rampatra * @since 2019-01-31 @@ -59,9 +57,9 @@ public static void main(String[] args) { l2.next = new Node(9); l2.next.next = new Node(9); - printList(l1); - printList(l2); - printList(sumLists(l1, l2)); + l1.print(); + l2.print(); + sumLists(l1, l2).print(); System.out.println("-----------"); l1 = new Node(9); @@ -71,9 +69,9 @@ public static void main(String[] args) { l2.next = new Node(9); l2.next.next = new Node(9); - printList(l1); - printList(l2); - printList(sumLists(l1, l2)); + l1.print(); + l2.print(); + sumLists(l1, l2).print(); System.out.println("-----------"); l1 = null; @@ -81,8 +79,8 @@ public static void main(String[] args) { l2.next = new Node(9); l2.next.next = new Node(8); - printList(l1); - printList(l2); - printList(sumLists(l1, l2)); + l1.print(); + l2.print(); + sumLists(l1, l2).print(); } } diff --git a/src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java b/src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java new file mode 100644 index 00000000..8e96d7eb --- /dev/null +++ b/src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java @@ -0,0 +1,91 @@ +package com.leetcode.linkedlists; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/plus-one-linked-list/ + * Problem Description: Given a non-empty single linked list representing a number where the head is the + * most significant bit, add one to the number and modify the same linked list. + * + * @author rampatra + * @since 2019-06-19 + */ +public class AddOneToNumberInList { + + + /** + * Add {@code one} to the number represented by linked list {@code head}. + * + * @param head the starting node of the linked list + * @return the head of the linked list after adding {@code one} + */ + private static Node addOne(Node head) { + Node currOrig = reverse(head); + Node currRes = null; + Node res = null; + + int sum = 1; + int carry = 0; + int rem; + + while (currOrig != null) { + sum += carry + currOrig.val; + rem = sum % 10; + carry = sum / 10; + + if (res == null) { + res = currRes = new Node(rem); + } else { + currRes.next = new Node(rem); + currRes = currRes.next; + } + + sum = 0; + currOrig = currOrig.next; + } + + if (carry != 0) { + currRes.next = new Node(carry); + } + + return reverse(res); + } + + private static Node reverse(Node head) { + Node prev = null; + Node curr = head; + Node next; + + while (curr != null) { + next = curr.next; + curr.next = prev; + + prev = curr; + curr = next; + } + + return prev; + } + + + public static void main(String[] args) { + Node node = new Node(9); + node.next = new Node(9); + node.next.next = new Node(9); + node.print(); + addOne(node).print(); + + System.out.println("---------"); + + node = new Node(1); + node.next = new Node(9); + node.next.next = new Node(9); + node.print(); + addOne(node).print(); + + System.out.println("---------"); + + node = new Node(0); + node.print(); + addOne(node).print(); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/linkedlists/Node.java b/src/main/java/com/leetcode/linkedlists/Node.java new file mode 100644 index 00000000..3276413f --- /dev/null +++ b/src/main/java/com/leetcode/linkedlists/Node.java @@ -0,0 +1,23 @@ +package com.leetcode.linkedlists; + +/** + * @author rampatra + * @since 21/11/2018 + */ +class Node { + int val; + Node next; + + Node(int val) { + this.val = val; + } + + public void print() { + Node curr = this; + while (curr.next != null) { + System.out.print(curr.val + "->"); + curr = curr.next; + } + System.out.println(curr.val); + } +} From b11f798038804c3f978365562a86c4e4de97b5fb Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 19 Jun 2019 16:52:44 +0100 Subject: [PATCH 09/70] Minor correction in question --- .../java/com/leetcode/linkedlists/AddOneToNumberInList.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java b/src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java index 8e96d7eb..9f0a029c 100644 --- a/src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java +++ b/src/main/java/com/leetcode/linkedlists/AddOneToNumberInList.java @@ -4,7 +4,7 @@ * Level: Easy * Problem Link: https://leetcode.com/problems/plus-one-linked-list/ * Problem Description: Given a non-empty single linked list representing a number where the head is the - * most significant bit, add one to the number and modify the same linked list. + * most significant bit, add one to the number and return a new linked list. * * @author rampatra * @since 2019-06-19 From 4d4353a31372e227fd86b25bc6774050174563a3 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Thu, 20 Jun 2019 22:08:57 +0100 Subject: [PATCH 10/70] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..f344b865 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: rampatra # Replace with a single Patreon username +open_collective: jbot # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: https://www.paypal.me/ramswaroop # Replace with a single custom sponsorship URL From 035140bc702506ac8a1013101aaaba8b29eeb55f Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 30 Jun 2019 23:15:03 +0100 Subject: [PATCH 11/70] Added basic producer/consumer --- .../java/advanced/JavaVisitorPattern.java | 8 ++ .../hackerrank/java/bignumber/BigDecimal.java | 40 +++++++++ .../java/com/rampatra/threads/NamePrint.java | 13 +-- .../ProducerConsumerUsingWaitNotify.java | 84 +++++++++++++++++++ .../com/rampatra/threads/SimpleDeadlock.java | 2 + 5 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java create mode 100644 src/main/java/com/hackerrank/java/bignumber/BigDecimal.java create mode 100644 src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java diff --git a/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java b/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java new file mode 100644 index 00000000..a40151be --- /dev/null +++ b/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java @@ -0,0 +1,8 @@ +package com.hackerrank.java.advanced; + +/** + * @author rampatra + * @since 2019-06-22 + */ +public class JavaVisitorPattern { +} diff --git a/src/main/java/com/hackerrank/java/bignumber/BigDecimal.java b/src/main/java/com/hackerrank/java/bignumber/BigDecimal.java new file mode 100644 index 00000000..7e1b804e --- /dev/null +++ b/src/main/java/com/hackerrank/java/bignumber/BigDecimal.java @@ -0,0 +1,40 @@ +package com.hackerrank.java.bignumber; + +import java.util.Arrays; +import java.util.List; +import java.util.Scanner; + +/** + * Problem Link: https://www.hackerrank.com/challenges/java-bigdecimal/ + * + * @author rampatra + * @since 2019-06-22 + */ +class BigDecimal { + public static void main(String[] args) { + //Input + Scanner sc = new Scanner(System.in); + int n = sc.nextInt(); + String[] s = new String[n + 2]; + for (int i = 0; i < n; i++) { + s[i] = sc.next(); + } + sc.close(); + + //Write your code here + s = Arrays.copyOfRange(s, 0, s.length - 2); + List input = Arrays.asList(s); + Arrays.sort(s, (s1, s2) -> { + int compare = new java.math.BigDecimal(s2).compareTo(new java.math.BigDecimal(s1)); + if (compare == 0) { + return Integer.compare(input.indexOf(s1), input.indexOf(s2)); + } + return compare; + }); + + //Output + for (int i = 0; i < n; i++) { + System.out.println(s[i]); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/rampatra/threads/NamePrint.java b/src/main/java/com/rampatra/threads/NamePrint.java index b87f3e5a..05e19820 100644 --- a/src/main/java/com/rampatra/threads/NamePrint.java +++ b/src/main/java/com/rampatra/threads/NamePrint.java @@ -1,13 +1,10 @@ package com.rampatra.threads; /** - * Created by IntelliJ IDEA. - *

- * Question: Print first name and last name (in order) using two different threads multiple times. + * Problem Description: Print first name and last name (in order) using two different threads 1000 times. * * @author rampatra * @since 10/6/15 - * @time: 7:10 PM */ public class NamePrint { @@ -21,7 +18,9 @@ public void run() { for (int i = 0; i < 1000; i++) { try { // wait if first name is printed but not the last name - if (isFirstNamePrinted) lock.wait(); + if (isFirstNamePrinted) { + lock.wait(); + } } catch (InterruptedException e) { e.printStackTrace(); } @@ -40,7 +39,9 @@ public void run() { for (int i = 0; i < 1000; i++) { try { // wait if first name is not printed - if (!isFirstNamePrinted) lock.wait(); + if (!isFirstNamePrinted) { + lock.wait(); + } } catch (InterruptedException e) { e.printStackTrace(); } diff --git a/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java b/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java new file mode 100644 index 00000000..3c626401 --- /dev/null +++ b/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java @@ -0,0 +1,84 @@ +package com.rampatra.threads; + +/** + * Problem Description: A simple Producer/Consumer using Wait/Notify pattern. + * + * @author rampatra + * @since 2019-06-30 + */ +public class ProducerConsumerUsingWaitNotify { + + private static int currSize = 0; + private static int totalSize = 10; + private static int[] buffer = new int[totalSize]; + private static Object lock = new Object(); + + static class Producer { + void produce() throws InterruptedException { + synchronized (lock) { + if (isFull()) { + lock.wait(); + } + buffer[currSize++] = 1; + lock.notify(); + } + } + } + + static class Consumer { + void consume() throws InterruptedException { + synchronized (lock) { + if (isEmpty()) { + lock.wait(); + } + System.out.println(buffer[currSize--]); + lock.notify(); + } + } + } + + private static boolean isFull() { + return currSize >= totalSize - 1; // as index starts from zero + } + + private static boolean isEmpty() { + return currSize == 0; + } + + public static void main(String[] args) throws InterruptedException { + + Runnable producerTask = () -> { + for (int i = 0; i < 1000; i++) { + try { + new Producer().produce(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }; + + Runnable consumerTask = () -> { + for (int i = 0; i < 1000; i++) { + try { + new Consumer().consume(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }; + + Thread producer = new Thread(producerTask); + Thread consumer = new Thread(consumerTask); + + // start both the threads + producer.start(); + consumer.start(); + + // wait for both the threads to complete + producer.join(); + consumer.join(); + + // as produce() and consume() are called equal number of times, this should be zero in the end + System.out.println("Buffer Size: " + currSize); + } +} \ No newline at end of file diff --git a/src/main/java/com/rampatra/threads/SimpleDeadlock.java b/src/main/java/com/rampatra/threads/SimpleDeadlock.java index a9e41491..b3b749a4 100644 --- a/src/main/java/com/rampatra/threads/SimpleDeadlock.java +++ b/src/main/java/com/rampatra/threads/SimpleDeadlock.java @@ -5,6 +5,8 @@ import java.lang.management.ThreadMXBean; /** + * Problem Description: Deadlock example. + * * @author rampatra * @since 2019-03-13 */ From 2866ce43cedc0a1eedb0eb7c4ca6cf6efb4e44e2 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 11 Jul 2019 15:15:31 +0100 Subject: [PATCH 12/70] Added Producer Consumer using Lock Api --- .../threads/ProducerConsumerUsingLockApi.java | 106 ++++++++++++++++++ .../ProducerConsumerUsingWaitNotify.java | 5 +- 2 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/rampatra/threads/ProducerConsumerUsingLockApi.java diff --git a/src/main/java/com/rampatra/threads/ProducerConsumerUsingLockApi.java b/src/main/java/com/rampatra/threads/ProducerConsumerUsingLockApi.java new file mode 100644 index 00000000..4c1443e0 --- /dev/null +++ b/src/main/java/com/rampatra/threads/ProducerConsumerUsingLockApi.java @@ -0,0 +1,106 @@ +package com.rampatra.threads; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +/** + * Problem Description: A simple Producer/Consumer using the Lock and Condition Api pattern. For the language primitive, + * i.e, synchronize and wait/notify pattern, please see {@link ProducerConsumerUsingWaitNotify}. + *

+ *

+ * There are a few advantages of going with the Lock Api pattern instead of the language primitive synchronize and + * wait/notify pattern: + *

+ * - Can be interrupted which means that the application won't continue to run forever in weird situations. Consider this + * example, what happens if the Consumer starts first and there are no elements to consume and the Producer also fails + * due to some exception. In wait/notify the Consumer would stall forever. You would have to restart the JVM to get + * rid of this. However, with Lock api, you can use {@link Lock#lockInterruptibly()}. + *

+ * - Timed lock acquisition. You can try to acquire a lock and if it is not instantly available then do something else. + * See {@link Lock#tryLock()} to learn more. You can also wait for a certain amount of time before giving up with the + * {@link Lock#tryLock(long, TimeUnit)} method. This isn't possible with the primitive pattern. + *

+ * - A fair Lock generates a fair Condition. Fair here means the first thread in the waiting queue will be picked first + * by the scheduler. This is a costly operation so use it only when necessary. + * + * @author rampatra + * @since 2019-07-10 + */ +public class ProducerConsumerUsingLockApi { + + private static int currSize = 0; + private static int totalSize = 10; + private static int[] buffer = new int[totalSize]; + private static Lock lock = new ReentrantLock(); + private static Condition isEmpty = lock.newCondition(); + private static Condition isFull = lock.newCondition(); + + static class Producer { + static void produce() { + try { + + lock.lock(); + while (currSize >= totalSize) { + isFull.await(); + } + buffer[currSize++] = 1; + isEmpty.signal(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + } + + static class Consumer { + static void consume() { + try { + + lock.lock(); + while (currSize <= 0) { + isEmpty.await(); + } + System.out.println(buffer[--currSize]); + isFull.signal(); + + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } + } + + public static void main(String[] args) throws InterruptedException { + + ExecutorService executorService = Executors.newFixedThreadPool(2); + + Runnable producerTask = () -> { + for (int i = 0; i < 1000; i++) { + Producer.produce(); + } + }; + + Runnable consumerTask = () -> { + for (int i = 0; i < 1000; i++) { + Consumer.consume(); + } + }; + + executorService.submit(producerTask); + executorService.submit(consumerTask); + + executorService.awaitTermination(3000, TimeUnit.MILLISECONDS); + + // as produce() and consume() are called equal number of times, this should be zero in the end + System.out.println("Buffer Size: " + currSize); + + executorService.shutdown(); + } +} \ No newline at end of file diff --git a/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java b/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java index 3c626401..df65fa2f 100644 --- a/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java +++ b/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java @@ -1,7 +1,8 @@ package com.rampatra.threads; /** - * Problem Description: A simple Producer/Consumer using Wait/Notify pattern. + * Problem Description: A simple Producer/Consumer using Synchronize and Wait/Notify pattern. For a better + * solution, please see {@link ProducerConsumerUsingLockApi}. * * @author rampatra * @since 2019-06-30 @@ -31,7 +32,7 @@ void consume() throws InterruptedException { if (isEmpty()) { lock.wait(); } - System.out.println(buffer[currSize--]); + System.out.println(buffer[--currSize]); lock.notify(); } } From 82cbaa669fb8aef37e514a0567f3c989068b8248 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 11 Jul 2019 15:16:34 +0100 Subject: [PATCH 13/70] Made the lock object final --- .../com/rampatra/threads/ProducerConsumerUsingWaitNotify.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java b/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java index df65fa2f..da753f04 100644 --- a/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java +++ b/src/main/java/com/rampatra/threads/ProducerConsumerUsingWaitNotify.java @@ -12,7 +12,7 @@ public class ProducerConsumerUsingWaitNotify { private static int currSize = 0; private static int totalSize = 10; private static int[] buffer = new int[totalSize]; - private static Object lock = new Object(); + private static final Object lock = new Object(); static class Producer { void produce() throws InterruptedException { From 904753ca14282a350bccb62b5067e424b4594e66 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 22 Jul 2019 14:48:59 +0100 Subject: [PATCH 14/70] Merge Intervals done --- .../com/leetcode/arrays/MergeIntervals.java | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/main/java/com/leetcode/arrays/MergeIntervals.java diff --git a/src/main/java/com/leetcode/arrays/MergeIntervals.java b/src/main/java/com/leetcode/arrays/MergeIntervals.java new file mode 100644 index 00000000..3efe59e0 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/MergeIntervals.java @@ -0,0 +1,75 @@ +package com.leetcode.arrays; + +import java.util.Arrays; +import java.util.Comparator; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/merge-intervals/ + * Problem Description: + *

+ * Given a collection of intervals, merge all overlapping intervals. + *

+ * Example 1: + * Input: [[1,3],[2,6],[8,10],[15,18]] + * Output: [[1,6],[8,10],[15,18]] + * Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6]. + *

+ * Example 2: + * Input: [[1,4],[4,5]] + * Output: [[1,5]] + * Explanation: Intervals [1,4] and [4,5] are considered overlapping. + * + * @author rampatra + * @since 2019-07-22 + */ +public class MergeIntervals { + + /** + * Time complexity: O(n log n) + * Space complexity: O(n) + * Runtime: 6 ms + * + * @param intervals a list of intervals, may not be sorted + * @return a list of intervals, with overlapping intervals merged + */ + public static int[][] merge(int[][] intervals) { + // some validations + if (intervals.length == 0) return new int[0][2]; + + // we first sort the intervals based on their start times + Arrays.sort(intervals, new IntervalComparator()); + + int[][] mergedIntervals = new int[intervals.length][2]; + int lastMergedIndex = 0; + mergedIntervals[lastMergedIndex] = intervals[0]; + + for (int i = 1; i < intervals.length; i++) { + if (isOverlap(mergedIntervals[lastMergedIndex], intervals[i])) { + // if two intervals overlap, then merge the two + mergedIntervals[lastMergedIndex] = new int[]{Math.min(mergedIntervals[lastMergedIndex][0], intervals[i][0]), + Math.max(mergedIntervals[lastMergedIndex][1], intervals[i][1])}; + } else { + mergedIntervals[++lastMergedIndex] = intervals[i]; + } + } + + return Arrays.copyOfRange(mergedIntervals, 0, lastMergedIndex + 1); + } + + private static boolean isOverlap(int[] interval1, int[] interval2) { + return interval1[0] <= interval2[0] && interval1[1] >= interval2[0]; + } + + private static class IntervalComparator implements Comparator { + @Override + public int compare(int[] interval1, int[] interval2) { + return interval1[0] - interval2[0]; + } + } + + public static void main(String[] args) { + System.out.println(Arrays.deepToString(merge(new int[][]{{1, 3}, {2, 6}, {8, 10}, {15, 18}}))); + System.out.println(Arrays.deepToString(merge(new int[][]{{1, 4}, {4, 5}}))); + } +} \ No newline at end of file From 775fed8bf1b0b9dca546fa280afdb121ede2a9d0 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Tue, 23 Jul 2019 22:25:26 +0100 Subject: [PATCH 15/70] Insert Interval done --- .../com/leetcode/arrays/InsertInterval.java | 78 +++++++++++++++++++ .../com/leetcode/arrays/MergeIntervals.java | 3 + 2 files changed, 81 insertions(+) create mode 100644 src/main/java/com/leetcode/arrays/InsertInterval.java diff --git a/src/main/java/com/leetcode/arrays/InsertInterval.java b/src/main/java/com/leetcode/arrays/InsertInterval.java new file mode 100644 index 00000000..519ea854 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/InsertInterval.java @@ -0,0 +1,78 @@ +package com.leetcode.arrays; + +import java.util.Arrays; + +/** + * Level: Hard + * Problem Link: https://leetcode.com/problems/insert-interval/ + * Problem Description: + * Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary). + *

+ * You may assume that the intervals were initially sorted according to their start times. + *

+ * Example 1: + * Input: intervals = [[1,3],[6,9]], newInterval = [2,5] + * Output: [[1,5],[6,9]] + *

+ * Example 2: + * Input: intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8] + * Output: [[1,2],[3,10],[12,16]] + * Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10]. + *

+ * Companies: LinkedIn + * Related: {@link MergeIntervals}. + * + * @author rampatra + * @since 2019-07-23 + */ +public class InsertInterval { + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * Runtime: 2 ms. + * + * @param intervals + * @param newInterval + * @return + */ + public static int[][] insert(int[][] intervals, int[] newInterval) { + if (intervals.length == 0 && newInterval.length == 0) { + return new int[][]{}; + } else if (intervals.length == 0) { + return new int[][]{newInterval}; + } + + int[][] mergedIntervals = new int[intervals.length + 1][2]; + int j = 0; + + for (int i = 0; i < intervals.length; i++) { + if (newInterval == null || newInterval[0] > intervals[i][1]) { // newInterval is after the ith interval + mergedIntervals[j++] = intervals[i]; + } else if (newInterval[1] < intervals[i][0]) { // newInterval is before the ith interval + mergedIntervals[j++] = newInterval; + mergedIntervals[j++] = intervals[i]; + newInterval = null; + } else { // if overlapping + newInterval[0] = Math.min(newInterval[0], intervals[i][0]); + newInterval[1] = Math.max(newInterval[1], intervals[i][1]); + } + } + + if (newInterval != null) { + mergedIntervals[j++] = newInterval; + } + + return Arrays.copyOfRange(mergedIntervals, 0, j); + } + + public static void main(String[] args) { + System.out.println(Arrays.deepToString(insert(new int[][]{}, new int[]{}))); + System.out.println(Arrays.deepToString(insert(new int[][]{}, new int[]{5, 7}))); + System.out.println(Arrays.deepToString(insert(new int[][]{{1, 5}}, new int[]{0, 0}))); + System.out.println(Arrays.deepToString(insert(new int[][]{{1, 5}}, new int[]{2, 3}))); + System.out.println(Arrays.deepToString(insert(new int[][]{{2, 5}, {6, 7}, {8, 9}}, new int[]{0, 1}))); + System.out.println(Arrays.deepToString(insert(new int[][]{{1, 3}, {6, 9}}, new int[]{2, 5}))); + System.out.println(Arrays.deepToString(insert(new int[][]{{1, 2}, {3, 5}, {6, 7}, {8, 10}, {12, 16}}, new int[]{4, 8}))); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/MergeIntervals.java b/src/main/java/com/leetcode/arrays/MergeIntervals.java index 3efe59e0..58f56ebc 100644 --- a/src/main/java/com/leetcode/arrays/MergeIntervals.java +++ b/src/main/java/com/leetcode/arrays/MergeIntervals.java @@ -19,6 +19,9 @@ * Input: [[1,4],[4,5]] * Output: [[1,5]] * Explanation: Intervals [1,4] and [4,5] are considered overlapping. + *

+ * Companies: LinkedIn + * Related: {@link InsertInterval}. * * @author rampatra * @since 2019-07-22 From dc0b538a72fa8f23ac294d32d68444611417384f Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 24 Jul 2019 22:50:56 +0100 Subject: [PATCH 16/70] Added junit + paint house 2 --- pom.xml | 8 + .../java/advanced/JavaVisitorPattern.java | 220 +++++++++++++++++- .../com/leetcode/arrays/InsertInterval.java | 2 +- .../dynamicprogramming/PaintHouse.java | 50 ++++ .../dynamicprogramming/PaintHouseII.java | 120 ++++++++++ 5 files changed, 398 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java create mode 100644 src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java diff --git a/pom.xml b/pom.xml index 84c22245..43d083ac 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,14 @@ ${java.version} + + + junit + junit + 4.12 + + + release diff --git a/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java b/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java index a40151be..5f91e9b5 100644 --- a/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java +++ b/src/main/java/com/hackerrank/java/advanced/JavaVisitorPattern.java @@ -1,8 +1,226 @@ package com.hackerrank.java.advanced; +import java.util.*; + /** + * Level: Medium + * Problem Link: https://www.hackerrank.com/challenges/java-vistor-pattern/ + * * @author rampatra * @since 2019-06-22 */ -public class JavaVisitorPattern { +enum Color { + RED, GREEN +} + +abstract class Tree { + + private int value; + private Color color; + private int depth; + + public Tree(int value, Color color, int depth) { + this.value = value; + this.color = color; + this.depth = depth; + } + + public int getValue() { + return value; + } + + public Color getColor() { + return color; + } + + public int getDepth() { + return depth; + } + + public abstract void accept(TreeVis visitor); + + +} + +class TreeNode extends Tree { + + private ArrayList children = new ArrayList<>(); + + public TreeNode(int value, Color color, int depth) { + super(value, color, depth); + } + + public void accept(TreeVis visitor) { + visitor.visitNode(this); + + for (Tree child : children) { + child.accept(visitor); + } + } + + public void addChild(Tree child) { + children.add(child); + } +} + +class TreeLeaf extends Tree { + + public TreeLeaf(int value, Color color, int depth) { + super(value, color, depth); + } + + public void accept(TreeVis visitor) { + visitor.visitLeaf(this); + } +} + +abstract class TreeVis { + public abstract int getResult(); + + public abstract void visitNode(TreeNode node); + + public abstract void visitLeaf(TreeLeaf leaf); + +} + +class SumInLeavesVisitor extends TreeVis { + int nodeSum = 0; + int leafSum = 0; + + public int getResult() { + //implement this + return leafSum; + } + + public void visitNode(TreeNode node) { + //implement this + //nodeSum += node.getValue(); + } + + public void visitLeaf(TreeLeaf leaf) { + //implement this + leafSum += leaf.getValue(); + } +} + +class ProductOfRedNodesVisitor extends TreeVis { + int prodOfRedNodesAndLeaves = 1; + private final int M = 1000000007; + + public int getResult() { + //implement this + return prodOfRedNodesAndLeaves; + } + + public void visitNode(TreeNode node) { + //implement this + if (node.getColor() == Color.RED) { + prodOfRedNodesAndLeaves *= (node.getValue() % M); + } + } + + public void visitLeaf(TreeLeaf leaf) { + //implement this + if (leaf.getColor() == Color.RED) { + prodOfRedNodesAndLeaves *= (leaf.getValue() % M); + } + } +} + +class FancyVisitor extends TreeVis { + int sumOfNodesAtEvenDepth = 0; + int sumOfGreenLeaves = 0; + + public int getResult() { + //implement this + return Math.abs(sumOfNodesAtEvenDepth - sumOfGreenLeaves); + } + + public void visitNode(TreeNode node) { + //implement this + if (node.getDepth() % 2 == 0) { + sumOfNodesAtEvenDepth += node.getValue(); + } + } + + public void visitLeaf(TreeLeaf leaf) { + //implement this + if (leaf.getColor() == Color.GREEN) { + sumOfGreenLeaves += leaf.getValue(); + } + } } + +public class JavaVisitorPattern { + + public static Tree solve() { + //read the tree from STDIN and return its root as a return value of this function + Scanner s = new Scanner(System.in); + + int numOfNodes = s.nextInt(); + int[] nodeValues = new int[numOfNodes]; + int[] nodeColors = new int[numOfNodes]; + Map> parentToChildMap = new HashMap<>(); + Map childToParentMap = new HashMap<>(); + + for (int i = 0; i < numOfNodes; i++) { + nodeValues[i] = s.nextInt(); + } + for (int i = 0; i < numOfNodes; i++) { + nodeColors[i] = s.nextInt(); + } + for (int i = 0; i < numOfNodes - 1; i++) { + int parentIndex = s.nextInt(); + int childIndex = s.nextInt(); + + Set children = parentToChildMap.get(parentIndex - 1) != null ? parentToChildMap.get(parentIndex - 1) : new HashSet<>(); + children.add(childIndex - 1); + parentToChildMap.put(parentIndex - 1, children); + childToParentMap.put(childIndex - 1, parentIndex - 1); + } + + List nodes = new ArrayList<>(numOfNodes); + for (int i = 0; i < numOfNodes; i++) { + + int depth = childToParentMap.get(i) == null ? -1 : nodes.get(childToParentMap.get(i)).getDepth(); + + if (parentToChildMap.get(i) != null) { + nodes.add(new TreeNode(nodeValues[i], nodeColors[i] == 0 ? Color.RED : Color.GREEN, depth + 1)); + } else { + nodes.add(new TreeLeaf(nodeValues[i], nodeColors[i] == 0 ? Color.RED : Color.GREEN, depth + 1)); + } + } + + + for (Map.Entry> entry : parentToChildMap.entrySet()) { + + TreeNode parent = (TreeNode) nodes.get(entry.getKey()); + + for (Integer childIndex : entry.getValue()) { + parent.addChild(nodes.get(childIndex)); + } + } + + return nodes.get(0); + } + + + public static void main(String[] args) { + Tree root = solve(); + SumInLeavesVisitor vis1 = new SumInLeavesVisitor(); + ProductOfRedNodesVisitor vis2 = new ProductOfRedNodesVisitor(); + FancyVisitor vis3 = new FancyVisitor(); + + root.accept(vis1); + root.accept(vis2); + root.accept(vis3); + + int res1 = vis1.getResult(); + int res2 = vis2.getResult(); + int res3 = vis3.getResult(); + + System.out.println(res1); + System.out.println(res2); + System.out.println(res3); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/InsertInterval.java b/src/main/java/com/leetcode/arrays/InsertInterval.java index 519ea854..52155f19 100644 --- a/src/main/java/com/leetcode/arrays/InsertInterval.java +++ b/src/main/java/com/leetcode/arrays/InsertInterval.java @@ -19,7 +19,7 @@ * Output: [[1,2],[3,10],[12,16]] * Explanation: Because the new interval [4,8] overlaps with [3,5],[6,7],[8,10]. *

- * Companies: LinkedIn + * Companies: LinkedIn. * Related: {@link MergeIntervals}. * * @author rampatra diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java new file mode 100644 index 00000000..ae5db698 --- /dev/null +++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java @@ -0,0 +1,50 @@ +package com.leetcode.dynamicprogramming; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/paint-house/ (premium) + * Problem Description: + * There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. The cost + * of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent + * houses have the same color. The cost of painting each house with a certain color is represented by a n x 3 cost matrix. + *

+ * For example, costs[0][0] is the cost of painting house 0 with color red; costs[1][2] is the cost of painting + * house 1 with color green, and so on... Find the minimum cost to paint all houses. + *

+ * Companies: LinkedIn. + * Related: {@link PaintHouseII}. + * + * @author rampatra + * @since 2019-07-23 + */ +public class PaintHouse { + + /** + * @param costs of coloring the houses with red, blue, and green respectively. 1st row represents house 1, 2nd row + * house 2 and so on + * @return the minimum cost to paint all houses such that no two adjacent houses are of same color + */ + public static int minCost(int[][] costs) { + if (costs == null || costs.length == 0) return 0; + + for (int i = 1; i < costs.length; i++) { + costs[i][0] += Math.min(costs[i - 1][1], costs[i - 1][2]); + costs[i][1] += Math.min(costs[i - 1][0], costs[i - 1][2]); + costs[i][2] += Math.min(costs[i - 1][0], costs[i - 1][1]); + } + + int lastRow = costs.length - 1; + return Math.min(Math.min(costs[lastRow][0], costs[lastRow][1]), costs[lastRow][2]); + } + + public static void main(String[] args) { + System.out.println(minCost(new int[][]{ + })); + + System.out.println(minCost(new int[][]{ + {2, 3, 4}, + {5, 7, 6}, + {8, 7, 2} + })); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java new file mode 100644 index 00000000..4c44e28d --- /dev/null +++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java @@ -0,0 +1,120 @@ +package com.leetcode.dynamicprogramming; + +import static org.junit.Assert.assertEquals; + +/** + * Level: Hard + * Problem Link: https://leetcode.com/problems/paint-house-ii/ (premium) + * Problem Description: + * There are a row of n houses, each house can be painted with one of the m colors. + * The cost of painting each house with a certain color is different. + * You have to paint all the houses such that no two adjacent houses have the same color. + *

+ * The cost of painting each house with a certain color is represented by a n x m cost matrix. + *

+ * For example, costs[0][0] is the cost of painting house 0 with color 0; + * costs[1][2] is the cost of painting house 1 with color 2, and so on... + * Find the minimum cost to paint all houses. + *

+ * Note: All costs are positive integers. + *

+ * Follow up: Could you solve it in O(n * m) runtime? // TODO + * + * Companies: LinkedIn. + * Related: {@link PaintHouse}. + * + * @author rampatra + * @since 2019-07-24 + */ +public class PaintHouseII { + + /** + * The approach is similar to {@link PaintHouse} but slightly complex as the number of colors are arbitrary + * instead of the 3 fixed colors. So, we use two additional for loops to cycle through all the colors. + * Time Complexity: O(n * m * m) + * Space Complexity: O(1) + * + * @param costs the costs of coloring the house, each row represents the cost of coloring a particular + * house with different colors + * @return the minimum cost to paint all houses such that no two adjacent houses are of same color + */ + public static int minCost(int[][] costs) { + if (costs == null || costs.length == 0) return 0; + + for (int i = 1; i < costs.length; i++) { + for (int j = 0; j < costs[0].length; j++) { + int min = Integer.MAX_VALUE; + // loop through all colors for the previous house except the color of the current house + for (int k = 0; k < costs[0].length; k++) { + if (k != j) { + min = Math.min(costs[i - 1][k], min); + } + } + costs[i][j] += min; + } + } + + int minCost = Integer.MAX_VALUE; + for (int i = 0; i < costs[0].length; i++) { + minCost = Math.min(costs[costs.length - 1][i], minCost); + } + + return minCost; + } + + public static void main(String[] args) { + assertEquals(0, minCost(new int[][]{})); + + assertEquals(10, minCost(new int[][]{ + {2, 3, 4}, + {5, 7, 6}, + {8, 7, 2} + })); + + assertEquals(10, minCost(new int[][]{{10, 30, 20}})); + + assertEquals(3, minCost(new int[][]{{1, 1, 1}, + {1, 1, 1}, + {1, 1, 1}})); + + assertEquals(5, minCost(new int[][]{{1, 2, 3}, + {3, 2, 1}, + {2, 2, 2}, + {3, 1, 2}})); + + assertEquals(10, minCost(new int[][]{{17, 2, 17}, + {16, 16, 5}, + {14, 3, 19}})); + + assertEquals(5, minCost(new int[][]{{1, 5, 3}, + {2, 9, 4}})); + + assertEquals(8, minCost(new int[][]{{8}})); + + assertEquals(143, minCost(new int[][]{{12, 1, 19}, + {15, 1, 10}, + {3, 11, 10}, + {9, 3, 10}, + {4, 8, 7}, + {4, 18, 2}, + {16, 6, 6}, + {3, 3, 6}, + {10, 18, 16}, + {5, 4, 8}, + {5, 3, 16}, + {11, 8, 19}, + {18, 15, 18}, + {16, 4, 15}, + {10, 7, 13}, + {11, 10, 14}, + {3, 9, 8}, + {5, 2, 2}, + {3, 2, 5}, + {2, 19, 14}, + {17, 3, 6}, + {6, 4, 17}, + {5, 15, 19}, + {2, 14, 14}, + {19, 4, 16}})); + } +} From ac90ee642b8f6186144cd3a737c87c6713a9b900 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 25 Jul 2019 22:21:12 +0100 Subject: [PATCH 17/70] can place flowers done --- .../com/leetcode/arrays/CanPlaceFlowers.java | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/main/java/com/leetcode/arrays/CanPlaceFlowers.java diff --git a/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java b/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java new file mode 100644 index 00000000..36e8a491 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java @@ -0,0 +1,67 @@ +package com.leetcode.arrays; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/can-place-flowers/ + * Problem Description: + * Suppose you have a long flowerBed in which some of the plots are planted and some are not. However, flowers cannot + * be planted in adjacent plots - they would compete for water and both would die. + *

+ * Given a flowerBed (represented as an array containing 0 and 1, where 0 means empty and 1 means not empty), and a + * number n, return if n new flowers can be planted in it without violating the no-adjacent-flowers rule. + *

+ * Example 1: + * Input: flowerBed = [1,0,0,0,1], n = 1 + * Output: True + *

+ * Example 2: + * Input: flowerBed = [1,0,0,0,1], n = 2 + * Output: False + *

+ * Note: + * The input array won't violate no-adjacent-flowers rule. + * The input array size is in the range of [1, 20000]. + * n is a non-negative integer which won't exceed the input array size. + * + * @author rampatra + * @since 2019-07-24 + */ +public class CanPlaceFlowers { + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * Runtime: 1 ms. + * + * @param flowerBed + * @param n + * @return + */ + public static boolean canPlaceFlowers(int[] flowerBed, int n) { + int i = 0, count = 0; + while (i < flowerBed.length) { + if (flowerBed[i] == 0 && (i == 0 || flowerBed[i - 1] == 0) && (i == flowerBed.length - 1 || flowerBed[i + 1] == 0)) { + flowerBed[i++] = 1; + count++; + } + if (count >= n) + return true; + i++; + } + return false; + } + + public static void main(String[] args) { + assertTrue(canPlaceFlowers(new int[]{0}, 0)); + assertTrue(canPlaceFlowers(new int[]{0}, 1)); + assertTrue(canPlaceFlowers(new int[]{1}, 0)); + assertFalse(canPlaceFlowers(new int[]{1}, 1)); + assertTrue(canPlaceFlowers(new int[]{1, 0, 0, 0, 1}, 1)); + assertFalse(canPlaceFlowers(new int[]{1, 0, 0, 0, 1}, 2)); + assertFalse(canPlaceFlowers(new int[]{1, 0, 0, 0, 0, 1}, 2)); + assertTrue(canPlaceFlowers(new int[]{1, 0, 0, 0, 1, 0, 0}, 2)); + } +} \ No newline at end of file From 511a132dfb41cf019326c0ac4a98ef04dee7f1ad Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 25 Jul 2019 23:32:16 +0100 Subject: [PATCH 18/70] Symmetric Tree Recursive solution done --- .../com/leetcode/trees/SymmetricTree.java | 77 +++++++++++++++++++ .../java/com/leetcode/trees/TreeNode.java | 16 ++++ 2 files changed, 93 insertions(+) create mode 100644 src/main/java/com/leetcode/trees/SymmetricTree.java create mode 100644 src/main/java/com/leetcode/trees/TreeNode.java diff --git a/src/main/java/com/leetcode/trees/SymmetricTree.java b/src/main/java/com/leetcode/trees/SymmetricTree.java new file mode 100644 index 00000000..bd536c9a --- /dev/null +++ b/src/main/java/com/leetcode/trees/SymmetricTree.java @@ -0,0 +1,77 @@ +package com.leetcode.trees; + +import static org.junit.Assert.assertTrue; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/symmetric-tree/ + * Problem Description: + * Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). + * + * For example, this binary tree [1,2,2,3,4,4,3] is symmetric: + * + * 1 + * / \ + * 2 2 + * / \ / \ + * 3 4 4 3 + * + * + * But the following [1,2,2,null,3,null,3] is not: + * + * 1 + * / \ + * 2 2 + * \ \ + * 3 3 + * + * + * Note: + * Bonus points if you could solve it both recursively and iteratively. + * + * @author rampatra + * @since 2019-07-25 + */ +public class SymmetricTree { + + /** + * Time Complexity: O(n) Because we traverse the entire input tree once, the total run time is O(n), where n is + * the total number of nodes in the tree. + * Space Complexity: O(n) The number of recursive calls is bound by the height of the tree. In the worst case, the + * tree is linear and the height is in O(n). Therefore, space complexity due to recursive calls on the stack is + * O(n) in the worst case. + * Runtime: 0 ms. + * + * @param root + * @return + */ + public static boolean isSymmetric(TreeNode root) { + if (root == null) { + return true; + } + + return isSymmetric(root.left, root.right); + } + + private static boolean isSymmetric(TreeNode leftRoot, TreeNode rightRoot) { + if (leftRoot == null && rightRoot == null) { + return true; + } else if (leftRoot == null || rightRoot == null) { + return false; + } + + return isSymmetric(leftRoot.left, rightRoot.right) && isSymmetric(leftRoot.right, rightRoot.left) && leftRoot.val == rightRoot.val; + } + + public static void main(String[] args) { + TreeNode root = new TreeNode(1); + root.left = new TreeNode(2); + root.right = new TreeNode(2); + root.left.left = new TreeNode(4); + root.left.right = new TreeNode(3); + root.right.left = new TreeNode(3); + root.right.right = new TreeNode(4); + + assertTrue(isSymmetric(root)); + } +} diff --git a/src/main/java/com/leetcode/trees/TreeNode.java b/src/main/java/com/leetcode/trees/TreeNode.java new file mode 100644 index 00000000..632e7c3e --- /dev/null +++ b/src/main/java/com/leetcode/trees/TreeNode.java @@ -0,0 +1,16 @@ +package com.leetcode.trees; + +/** + * @author rampatra + * @since 2019-07-25 + */ +public class TreeNode { + + int val; + TreeNode left; + TreeNode right; + + public TreeNode(int val) { + this.val = val; + } +} \ No newline at end of file From 5d759f8eb4700af9a1cf4a9734b2fc428717250a Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sat, 27 Jul 2019 15:31:30 +0100 Subject: [PATCH 19/70] Iterative approach done for Symmetric Tree --- .../com/leetcode/trees/SymmetricTree.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/main/java/com/leetcode/trees/SymmetricTree.java b/src/main/java/com/leetcode/trees/SymmetricTree.java index bd536c9a..bfd4c6ae 100644 --- a/src/main/java/com/leetcode/trees/SymmetricTree.java +++ b/src/main/java/com/leetcode/trees/SymmetricTree.java @@ -1,5 +1,8 @@ package com.leetcode.trees; +import java.util.LinkedList; +import java.util.Queue; + import static org.junit.Assert.assertTrue; /** @@ -63,6 +66,42 @@ private static boolean isSymmetric(TreeNode leftRoot, TreeNode rightRoot) { return isSymmetric(leftRoot.left, rightRoot.right) && isSymmetric(leftRoot.right, rightRoot.left) && leftRoot.val == rightRoot.val; } + /** + * Time Complexity: O(n) Because we traverse the entire input tree once, the total run time is O(n), where n is the + * total number of nodes in the tree. + * Space Complexity: There is additional space required for the search queue. In the worst case, we have to + * insert O(n) nodes in the queue. Therefore, space complexity is O(n). + * Runtime: 1 ms. + * + * @param root + * @return + */ + public static boolean isSymmetricIterative(TreeNode root) { + if (root == null || (root.left == null && root.right == null)) return true; + if (root.left == null || root.right == null) return false; + + Queue queue = new LinkedList<>(); + queue.add(root.left); + queue.add(root.right); + + while (!queue.isEmpty()) { + TreeNode t1 = queue.poll(); + TreeNode t2 = queue.poll(); + + if (t1 == null && t2 == null) continue; + if (t1 == null || t2 == null) return false; + if (t1.val != t2.val) return false; + + // enqueue left and then right child of t1 but do the opposite for t2 + queue.add(t1.left); + queue.add(t2.right); + queue.add(t1.right); + queue.add(t2.left); + } + + return true; + } + public static void main(String[] args) { TreeNode root = new TreeNode(1); root.left = new TreeNode(2); @@ -73,5 +112,6 @@ public static void main(String[] args) { root.right.right = new TreeNode(4); assertTrue(isSymmetric(root)); + assertTrue(isSymmetricIterative(root)); } } From b0c095942c0d6d5771ff2f636eaf92432499be80 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Tue, 30 Jul 2019 10:23:34 +0100 Subject: [PATCH 20/70] Updated Junit version --- pom.xml | 8 ++++---- .../java/com/leetcode/arrays/NestedListWeightSumI.java | 8 ++++++++ src/main/java/com/leetcode/maps/RepeatedDnaSequence.java | 8 ++++++++ .../java/com/leetcode/stacks/ReversePolishNotation.java | 8 ++++++++ 4 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/leetcode/arrays/NestedListWeightSumI.java create mode 100644 src/main/java/com/leetcode/maps/RepeatedDnaSequence.java create mode 100644 src/main/java/com/leetcode/stacks/ReversePolishNotation.java diff --git a/pom.xml b/pom.xml index 43d083ac..4db680c0 100644 --- a/pom.xml +++ b/pom.xml @@ -49,16 +49,16 @@ UTF-8 1.8 - 1.4.0.RELEASE ${java.version} ${java.version} + - junit - junit - 4.12 + org.junit.jupiter + junit-jupiter-api + 5.5.1 diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java b/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java new file mode 100644 index 00000000..93451550 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java @@ -0,0 +1,8 @@ +package com.leetcode.arrays; + +/** + * @author rampatra + * @since 2019-07-27 + */ +public class NestedListWeightSumI { +} diff --git a/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java b/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java new file mode 100644 index 00000000..6be6e256 --- /dev/null +++ b/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java @@ -0,0 +1,8 @@ +package com.leetcode.maps; + +/** + * @author rampatra + * @since 2019-07-29 + */ +public class RepeatedDnaSequence { +} diff --git a/src/main/java/com/leetcode/stacks/ReversePolishNotation.java b/src/main/java/com/leetcode/stacks/ReversePolishNotation.java new file mode 100644 index 00000000..83a381a0 --- /dev/null +++ b/src/main/java/com/leetcode/stacks/ReversePolishNotation.java @@ -0,0 +1,8 @@ +package com.leetcode.stacks; + +/** + * @author rampatra + * @since 2019-07-27 + */ +public class ReversePolishNotation { +} From f836481b7edd5ff3c04570e6637ac89899c2fff9 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Tue, 30 Jul 2019 10:26:20 +0100 Subject: [PATCH 21/70] Updated JUnit version + Repeated DNA Sequence done --- .../com/leetcode/arrays/CanPlaceFlowers.java | 5 +- .../leetcode/arrays/NestedListWeightSumI.java | 8 ++ .../dynamicprogramming/PaintHouseII.java | 2 +- .../leetcode/maps/RepeatedDnaSequence.java | 63 +++++++++++++- .../stacks/ReversePolishNotation.java | 85 +++++++++++++++++++ .../com/leetcode/trees/SymmetricTree.java | 2 +- 6 files changed, 160 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java b/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java index 36e8a491..916499ac 100644 --- a/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java +++ b/src/main/java/com/leetcode/arrays/CanPlaceFlowers.java @@ -1,7 +1,8 @@ package com.leetcode.arrays; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Level: Easy diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java b/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java index 93451550..1367ed16 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java @@ -5,4 +5,12 @@ * @since 2019-07-27 */ public class NestedListWeightSumI { + + public long nestedSum(Object[] nestedList, long sum, int depth) { + return -1; + } + + public static void main(String[] args) { + + } } diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java index 4c44e28d..1c51ee68 100644 --- a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java +++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java @@ -1,6 +1,6 @@ package com.leetcode.dynamicprogramming; -import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; /** * Level: Hard diff --git a/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java b/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java index 6be6e256..28767ca4 100644 --- a/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java +++ b/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java @@ -1,8 +1,69 @@ package com.leetcode.maps; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * @author rampatra * @since 2019-07-29 */ public class RepeatedDnaSequence { -} + + /** + * Rabin-Karp Algorithm: https://brilliant.org/wiki/rabin-karp-algorithm/ + * + * @param s + * @return + */ + public static List findRepeatedDnaSequences(String s) { + if (s.length() < 10) return new ArrayList<>(); + + Set repeatedSequences = new HashSet<>(); + Map> hashToStringMap = new HashMap<>(); + long hashOfSequence = computeHash(s); + hashToStringMap.put(hashOfSequence, new HashSet() {{ + add(s.substring(0, 10)); + }}); + + long pow = (long) Math.pow(4, 9); + + for (int i = 10; i < s.length(); i++) { + hashOfSequence = (hashOfSequence - (pow * (s.charAt(i - 10) - 'A'))) * 4 + (s.charAt(i) - 'A'); + String subString = s.substring(i - 10 + 1, i + 1); + + if (hashToStringMap.get(hashOfSequence) != null && hashToStringMap.get(hashOfSequence).contains(subString)) { + repeatedSequences.add(subString); + continue; + } + + hashToStringMap.putIfAbsent(hashOfSequence, new HashSet<>()); + hashToStringMap.get(hashOfSequence).add(subString); + } + + return new ArrayList<>(repeatedSequences); + } + + private static long computeHash(String s) { + long hash = 0; + for (int i = 0; i < 10; i++) { + hash += (Math.pow(4, i) * (s.charAt(9 - i) - 'A')); + } + return hash; + } + + public static void main(String[] args) { + + assertEquals(new ArrayList<>(), + findRepeatedDnaSequences("AAAAACCC")); + + assertEquals(Arrays.asList("AAAAACCCCC", "CCCCCAAAAA"), + findRepeatedDnaSequences("AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT")); + + assertEquals(Collections.singletonList("AAAAAAAAAA"), + findRepeatedDnaSequences("AAAAAAAAAAAA")); + + assertEquals(Collections.singletonList("BBBBBBBBBB"), + findRepeatedDnaSequences("BBBBBBBBBBBB")); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/stacks/ReversePolishNotation.java b/src/main/java/com/leetcode/stacks/ReversePolishNotation.java index 83a381a0..f917099a 100644 --- a/src/main/java/com/leetcode/stacks/ReversePolishNotation.java +++ b/src/main/java/com/leetcode/stacks/ReversePolishNotation.java @@ -1,8 +1,93 @@ package com.leetcode.stacks; +import java.util.Stack; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** + * Level: Medium + * Problem Link: https://leetcode.com/problems/evaluate-reverse-polish-notation + * Problem Description: + * Evaluate the value of an arithmetic expression in Reverse Polish Notation. + *

+ * Valid operators are +, -, *, /. Each operand may be an integer or another expression. + *

+ * Note: + * Division between two integers should truncate toward zero. + * The given RPN expression is always valid. That means the expression would always evaluate to a result and there + * won't be any divide by zero operation. + *

+ * Example 1: + * Input: ["2", "1", "+", "3", "*"] + * Output: 9 + * Explanation: ((2 + 1) * 3) = 9 + *

+ * Example 2: + * Input: ["4", "13", "5", "/", "+"] + * Output: 6 + * Explanation: (4 + (13 / 5)) = 6 + *

+ * Example 3: + * Input: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"] + * Output: 22 + * Explanation: + * ((10 * (6 / ((9 + 3) * -11))) + 17) + 5 + * = ((10 * (6 / (12 * -11))) + 17) + 5 + * = ((10 * (6 / -132)) + 17) + 5 + * = ((10 * 0) + 17) + 5 + * = (0 + 17) + 5 + * = 17 + 5 + * = 22 + * * @author rampatra * @since 2019-07-27 */ public class ReversePolishNotation { + + /** + * Time Complexity: + * Space Complexity: + * Runtime: 5 ms. + * + * @param tokens + * @return + */ + public static int evalRPN(String[] tokens) { + int operand1; + int operand2; + + Stack stack = new Stack<>(); + + for (String s : tokens) { + switch (s) { + case "+": + stack.push(stack.pop() + stack.pop()); + break; + case "-": + operand1 = stack.pop(); + operand2 = stack.pop(); + stack.push(operand2 - operand1); + break; + case "*": + stack.push(stack.pop() * stack.pop()); + break; + case "/": + operand1 = stack.pop(); + operand2 = stack.pop(); + stack.push(operand2 / operand1); + break; + default: + stack.push(Integer.parseInt(s)); + } + } + + return stack.pop(); + } + + public static void main(String[] args) { + assertEquals(18, evalRPN(new String[]{"18"})); + assertEquals(9, evalRPN(new String[]{"2", "1", "+", "3", "*"})); + assertEquals(6, evalRPN(new String[]{"4", "13", "5", "/", "+"})); + assertEquals(22, evalRPN(new String[]{"10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"})); + } } diff --git a/src/main/java/com/leetcode/trees/SymmetricTree.java b/src/main/java/com/leetcode/trees/SymmetricTree.java index bfd4c6ae..093d9a6f 100644 --- a/src/main/java/com/leetcode/trees/SymmetricTree.java +++ b/src/main/java/com/leetcode/trees/SymmetricTree.java @@ -3,7 +3,7 @@ import java.util.LinkedList; import java.util.Queue; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Level: Easy From 9e3d03ce5e6d5b66989018d95a60dcbc65da615e Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 31 Jul 2019 21:47:07 +0100 Subject: [PATCH 22/70] Closest binary search tree value done --- .../com/leetcode/trees/ClosestBinarySearchTreeValueI.java | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java new file mode 100644 index 00000000..7bfb21c2 --- /dev/null +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java @@ -0,0 +1,8 @@ +package com.leetcode.trees; + +/** + * @author rampatra + * @since 2019-07-31 + */ +public class ClosestBinarySearchTreeValue { +} From 63a6b374b0fb66cfc9534b92148f0092eb932977 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 31 Jul 2019 21:47:48 +0100 Subject: [PATCH 23/70] Closest binary search tree value done --- .../leetcode/arrays/NestedListWeightSumI.java | 49 +++++++++++-- .../leetcode/maps/RepeatedDnaSequence.java | 22 +++++- .../trees/ClosestBinarySearchTreeValueI.java | 70 ++++++++++++++++++- 3 files changed, 135 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java b/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java index 1367ed16..5992920e 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java @@ -1,16 +1,57 @@ package com.leetcode.arrays; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** + * Level: Easy + * Problem Link: https://leetcode.com/problems/nested-list-weight-sum/ (premium) + * Problem Description: + * Given a nested list of integers, return the sum of all integers in the list weighted by their depth. Each element + * is either an integer, or a list – whose elements may also be integers or other lists. + *

+ * Example 1: + * Given the list [[1,1],2,[1,1]], return 10. (four 1’s at depth 2, one 2 at depth 1) + *

+ * Example 2: + * Given the list [1,[4,[6]]], return 27. (one 1 at depth 1, one 4 at depth 2, and one 6 at depth 3; 1 + 42 + 63 = 27) + * + * Note: For a more complex variant, see {@link NestedListWeightSumII}. + * * @author rampatra * @since 2019-07-27 */ public class NestedListWeightSumI { - public long nestedSum(Object[] nestedList, long sum, int depth) { - return -1; + /** + * Time Complexity: The algorithm takes O(N) time, where N is the total number of nested elements in the input + * list. For example, the list [ [[[[1]]]], 2 ] contains 4 nested lists and 2 nested integers (11 and 22), so N=6. + * Space Complexity: In terms of space, at most O(D) recursive calls are placed on the stack, where D is the + * maximum level of nesting in the input. For example, D=2 for the input [[1,1],2,[1,1]], and D=3 for the + * input [1,[4,[6]]]. + * + * @param nestedList + * @return + */ + public static long nestedSum(Object[] nestedList) { + return nestedSum(nestedList, 1); } - public static void main(String[] args) { + private static long nestedSum(Object[] nestedList, int depth) { + long sum = 0; + for (int i = 0; i < nestedList.length; i++) { + if (nestedList[i] instanceof Integer) { + sum += ((int) nestedList[i] * depth); + } else { + sum += nestedSum((Object[]) nestedList[i], depth + 1); + } + } + return sum; + } + public static void main(String[] args) { + assertEquals(0, nestedSum(new Object[]{})); + assertEquals(0, nestedSum(new Object[]{new Object[]{}})); + assertEquals(10, nestedSum(new Object[]{new Object[]{1, 1}, 2, new Object[]{1, 1}})); + assertEquals(27, nestedSum(new Object[]{1, new Object[]{4, new Object[]{6}}})); } -} +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java b/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java index 28767ca4..a4eddb4a 100644 --- a/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java +++ b/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java @@ -5,6 +5,20 @@ import static org.junit.jupiter.api.Assertions.assertEquals; /** + * Level: Medium + * Problem Link: https://leetcode.com/problems/repeated-dna-sequences/submissions/ + * Problem Description: + * All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACGAATTCCG". When + * studying DNA, it is sometimes useful to identify repeated sequences within the DNA. + * + * Write a function to find all the 10-letter-long sequences (substrings) that occur more than once in a DNA molecule. + * + * Example: + * Input: s = "AAAAACCCCCAAAAACCCCCCAAAAAGGGTTT" + * Output: ["AAAAACCCCC", "CCCCCAAAAA"] + * + * TODO: Figure another method which would have a better runtime. + * * @author rampatra * @since 2019-07-29 */ @@ -12,6 +26,13 @@ public class RepeatedDnaSequence { /** * Rabin-Karp Algorithm: https://brilliant.org/wiki/rabin-karp-algorithm/ + * Following Rabin-Karp's approach let's you avoid spurious hits (worst case scenario) but once the hash matches, + * you will have to compare and check the string you're searching. I tried to just rely on the hash and few test + * cases failed for me (https://leetcode.com/submissions/detail/247342702/). + *

+ * Time Complexity: + * Space Complexity: + * Runtime: 38 ms. * * @param s * @return @@ -53,7 +74,6 @@ private static long computeHash(String s) { } public static void main(String[] args) { - assertEquals(new ArrayList<>(), findRepeatedDnaSequences("AAAAACCC")); diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java index 7bfb21c2..a7de4bf3 100644 --- a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java @@ -1,8 +1,76 @@ package com.leetcode.trees; +import static org.junit.jupiter.api.Assertions.assertEquals; + /** + * Level: Easy + * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value/ + * Problem Description: + * * @author rampatra * @since 2019-07-31 */ -public class ClosestBinarySearchTreeValue { +public class ClosestBinarySearchTreeValueI { + + public static TreeNode findNodeWithClosestValue(TreeNode node, TreeNode parentNode, int val, int diff) { + if (node == null) return parentNode; + + if (Math.abs(node.val - val) > diff) return parentNode; + + if (node.val > val) { + return findNodeWithClosestValue(node.left, node, val, Math.abs(node.val - val)); + } else { + return findNodeWithClosestValue(node.right, node, val, Math.abs(node.val - val)); + } + } + + public static void main(String[] args) { + + /* + BST looks like: + + 9 + / \ + 7 13 + / \ \ + 5 8 20 + / \ + 2 6 + */ + TreeNode root = new TreeNode(9); + root.left = new TreeNode(7); + root.right = new TreeNode(13); + root.left.left = new TreeNode(5); + root.left.right = new TreeNode(8); + root.left.left.left = new TreeNode(2); + root.left.left.right = new TreeNode(6); + root.right.right = new TreeNode(20); + + assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); + assertEquals(13, findNodeWithClosestValue(root, root, 13, Integer.MAX_VALUE).val); + assertEquals(9, findNodeWithClosestValue(root, root, 9, Integer.MAX_VALUE).val); + assertEquals(2, findNodeWithClosestValue(root, root, 2, Integer.MAX_VALUE).val); + assertEquals(2, findNodeWithClosestValue(root, root, 1, Integer.MAX_VALUE).val); + assertEquals(6, findNodeWithClosestValue(root, root, 6, Integer.MAX_VALUE).val); + assertEquals(13, findNodeWithClosestValue(root, root, 11, Integer.MAX_VALUE).val); // tie b/w 9 and 13 + + /* + BST looks like: + + 9 + / \ + 7 13 + / \ / \ + 5 8 13 20 + */ + root = new TreeNode(9); + root.left = new TreeNode(7); + root.right = new TreeNode(13); + root.left.left = new TreeNode(5); + root.left.right = new TreeNode(8); + root.right.left = new TreeNode(13); + root.right.right = new TreeNode(20); + + assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); + } } From 5e7a814a4ca7551798642a136937cfc695d62cb0 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 31 Jul 2019 22:27:35 +0100 Subject: [PATCH 24/70] Added some more comments and minor refactorings --- ...ightSumI.java => NestedListWeightSum.java} | 2 +- .../arrays/NestedListWeightSumII.java | 115 ++++++++++++++++++ .../leetcode/arrays/ShortestWordDistance.java | 64 ++++++++++ .../leetcode/maps/ShortestWordDistanceII.java | 34 ++++++ ...java => ClosestBinarySearchTreeValue.java} | 12 +- 5 files changed, 224 insertions(+), 3 deletions(-) rename src/main/java/com/leetcode/arrays/{NestedListWeightSumI.java => NestedListWeightSum.java} (98%) create mode 100644 src/main/java/com/leetcode/arrays/NestedListWeightSumII.java create mode 100644 src/main/java/com/leetcode/arrays/ShortestWordDistance.java create mode 100644 src/main/java/com/leetcode/maps/ShortestWordDistanceII.java rename src/main/java/com/leetcode/trees/{ClosestBinarySearchTreeValueI.java => ClosestBinarySearchTreeValue.java} (93%) diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java b/src/main/java/com/leetcode/arrays/NestedListWeightSum.java similarity index 98% rename from src/main/java/com/leetcode/arrays/NestedListWeightSumI.java rename to src/main/java/com/leetcode/arrays/NestedListWeightSum.java index 5992920e..b59a51ee 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSumI.java +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSum.java @@ -20,7 +20,7 @@ * @author rampatra * @since 2019-07-27 */ -public class NestedListWeightSumI { +public class NestedListWeightSum { /** * Time Complexity: The algorithm takes O(N) time, where N is the total number of nested elements in the input diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java new file mode 100644 index 00000000..85448337 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java @@ -0,0 +1,115 @@ +package com.leetcode.arrays; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/nested-list-weight-sum-ii/ (premium) + * Problem Description: + * Given a nested list of integers, return the sum of all integers in the list weighted by their depth. Each element + * is either an integer, or a list – whose elements may also be integers or other lists. + *

+ * Different from {@link NestedListWeightSum} where weight is increasing from root to leaf, now the weight is defined + * from bottom up, i.e., the leaf level integers have weight 1, and the root level integers have the largest weight. + *

+ * Example 1: + * Given the list [[1,1],2,[1,1]], return 8. (four 1’s at depth 1, one 2 at depth 2) + *

+ * Example 2: + * Given the list [1,[4,[6]]], return 17. (one 1 at depth 3, one 4 at depth 2, and one 6 at depth 1; 13 + 42 + 6*1 = 17) + *

+ * Note: For a simpler variant, see {@link NestedListWeightSum}. + * + * @author rampatra + * @since 2019-07-27 + */ +public class NestedListWeightSumII { + + /** + * @param nestedList + * @return + */ + public static long nestedSum(List nestedList) { + long weightedSum = 0; + long unweightedSum = 0; + Queue queue = new LinkedList<>(); + + for (NestedInteger nestedInteger : nestedList) { + if (nestedInteger.isInteger()) { + unweightedSum += nestedInteger.getInteger(); + } else { + queue.addAll(nestedInteger.getList()); + while (!queue.isEmpty()) { + NestedInteger ni = queue.poll(); + if (ni.isInteger()) { + unweightedSum += ni.getInteger(); + } else { + nestedList.addAll(ni.getList()); + } + } + unweightedSum += unweightedSum; + weightedSum = unweightedSum; + } + } + + return weightedSum; + } + + public static void main(String[] args) { + assertEquals(0, nestedSum(Collections.singletonList(new NestedInteger()))); + + assertEquals(0, nestedSum(Collections.singletonList(new NestedInteger().add(new NestedInteger())))); + + NestedInteger ni = new NestedInteger(2); + ni.add(new NestedInteger().add(new NestedInteger(1)).add(new NestedInteger(1))); + ni.add(new NestedInteger().add(new NestedInteger(1)).add(new NestedInteger(1))); + + assertEquals(10, nestedSum(Collections.singletonList(ni))); + + ni = new NestedInteger(1); + ni.add(new NestedInteger(4).add(new NestedInteger(6))); + + assertEquals(27, nestedSum(Collections.singletonList(ni))); + + /*assertEquals(10, nestedSum(new Object[]{new Object[]{1, 1}, 2, new Object[]{1, 1}})); + assertEquals(27, nestedSum(new Object[]{1, new Object[]{4, new Object[]{6}}}));*/ + } +} + +class NestedInteger { + + private Integer integer; + private List list; + + public NestedInteger() { + this.list = new ArrayList<>(); + } + + public NestedInteger(int integer) { + this.integer = integer; + this.list = new ArrayList<>(); + } + + public boolean isInteger() { + return this.integer != null; + } + + public Integer getInteger() { + return integer; + } + + public void setInteger(Integer integer) { + this.integer = integer; + } + + public List getList() { + return list; + } + + public NestedInteger add(NestedInteger nestedInteger) { + this.list.add(nestedInteger); + return this; + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java new file mode 100644 index 00000000..44e90d1a --- /dev/null +++ b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java @@ -0,0 +1,64 @@ +package com.leetcode.arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Problem Link: + * Problem Description: + * Given a list of words and two words word1 and word2, return the shortest distance between these two words in the + * list of words. + * + * Example 1: + * Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + * Given word1 = "coding", word2 = "practice", return 3. + * Given word1 = "makes", word2 = "coding", return 1. + * + * Note: You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. + * + * Lastly, for a more complex variant, see {@link com.leetcode.maps.ShortestWordDistanceII}. + * + * @author rampatra + * @since 2019-07-31 + */ +public class ShortestWordDistance { + + /** + * Time Complexity: + * Space Complexity: + * TODO + * + * @param words + * @param word1 + * @param word2 + * @return + */ + public static int findShortestDistance(String[] words, String word1, String word2) { + int startWord1 = Integer.MIN_VALUE; + int startWord2 = Integer.MAX_VALUE; + int minDistance = Integer.MAX_VALUE; + + for (int i = 0; i < words.length; i++) { + if (words[i].equals(word1)) { + startWord1 = i; + } + if (words[i].equals(word2)) { + startWord2 = i; + } + minDistance = Math.min(minDistance, Math.abs(startWord1 - startWord2)); + } + + return minDistance; + } + + public static void main(String[] args) { + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "practice", "coding")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "coding")); + assertEquals(0, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "perfect", "perfect")); + assertEquals(0, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "makes")); + } +} diff --git a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java new file mode 100644 index 00000000..6d5795c6 --- /dev/null +++ b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java @@ -0,0 +1,34 @@ +package com.leetcode.maps; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/shortest-word-distance-ii/ (premium) + * Problem Description: + * This is a follow up of Shortest Word Distance. The only difference is now you are given the list of words and + * your method will be called repeatedly many times with different parameters. How would you optimize it? + *

+ * Design a class which receives a list of words in the constructor, and implements a method that takes two words + * word1 and word2 and return the shortest distance between these two words in the list. + *

+ * Example 1: + * Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + * Given word1 = "coding”, word2 = "practice”, return 3. + * Given word1 = "makes", word2 = "coding", return 1. + *

+ * Note: You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. + *

+ * Lastly, for a simpler variant, see {@link com.leetcode.arrays.ShortestWordDistance}. + * + * @author rampatra + * @since 2019-07-31 + */ +public class ShortestWordDistanceII { + + public static int findShortestDistance(String[] words, String word1, String word2) { + return -1; + } + + public static void main(String[] args) { + + } +} diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java similarity index 93% rename from src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java rename to src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java index a7de4bf3..80367748 100644 --- a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueI.java +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java @@ -4,14 +4,22 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value/ + * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value/ (premium) * Problem Description: * * @author rampatra * @since 2019-07-31 */ -public class ClosestBinarySearchTreeValueI { +public class ClosestBinarySearchTreeValue { + /** + * + * @param node + * @param parentNode + * @param val + * @param diff + * @return + */ public static TreeNode findNodeWithClosestValue(TreeNode node, TreeNode parentNode, int val, int diff) { if (node == null) return parentNode; From 40c3eb1b6adfc61e5db7107a675a5c711c9d86af Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 2 Aug 2019 10:56:20 +0100 Subject: [PATCH 25/70] Leaves of binary tree: done --- .../leetcode/trees/LeavesOfBinaryTree.java | 97 +++++++++++++++++++ .../java/com/leetcode/trees/TreeNode.java | 5 + 2 files changed, 102 insertions(+) create mode 100644 src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java diff --git a/src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java b/src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java new file mode 100644 index 00000000..8dcd0c1f --- /dev/null +++ b/src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java @@ -0,0 +1,97 @@ +package com.leetcode.trees; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/find-leaves-of-binary-tree/ + * Problem Description: + * Given a binary tree, collect a tree's nodes as if you were doing this: Collect and remove all leaves, repeat + * until the tree is empty. + * + * Example: + * Input: [1,2,3,4,5] + * + * 1 + * / \ + * 2 3 + * / \ + * 4 5 + * + * Output: [[4,5,3],[2],[1]] + * + * Explanation: + * 1. Removing the leaves [4,5,3] would result in this tree: + * 1 + * / + * 2 + * + * 2. Now removing the leaf [2] would result in this tree: + * 1 + * + * 3. Now removing the leaf [1] would result in the empty tree: + * [] + * + * @author rampatra + * @since 2019-08-01 + */ +public class LeavesOfBinaryTree { + + /** + * THe idea is to perform a DFS and backtrack. While backtracking, check the height of the node and insert + * the node into the list indexed by their heights. + * Time Complexity: + * Space Complexity: + * Runtime: . + * + * @param root + * @return + */ + public static List> findLeavesOfBinaryTree(TreeNode root) { + List> levels = new ArrayList<>(); + findLeavesOfBinaryTree(root, levels); + return levels; + } + + private static int findLeavesOfBinaryTree(TreeNode root, List> levels) { + if (root == null) return -1; + + int leftHeight = findLeavesOfBinaryTree(root.left, levels); + int rightHeight = findLeavesOfBinaryTree(root.right, levels); + int height = Math.max(leftHeight, rightHeight) + 1; + + if (height >= levels.size()) { + levels.add(height, new ArrayList<>()); + } + levels.get(height).add(root); + + return height; + } + + public static void main(String[] args) { + /* + BST looks like: + + 4 + / \ + 1 7 + / \ \ + 3 8 20 + / \ + 2 6 + */ + TreeNode root = new TreeNode(4); + root.left = new TreeNode(1); + root.right = new TreeNode(7); + root.left.left = new TreeNode(3); + root.left.right = new TreeNode(8); + root.left.left.left = new TreeNode(2); + root.left.left.right = new TreeNode(6); + root.right.right = new TreeNode(20); + + assertEquals("[[2, 6, 8, 20], [3, 7], [1], [4]]", findLeavesOfBinaryTree(root).toString()); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/trees/TreeNode.java b/src/main/java/com/leetcode/trees/TreeNode.java index 632e7c3e..4c4c2569 100644 --- a/src/main/java/com/leetcode/trees/TreeNode.java +++ b/src/main/java/com/leetcode/trees/TreeNode.java @@ -13,4 +13,9 @@ public class TreeNode { public TreeNode(int val) { this.val = val; } + + @Override + public String toString() { + return val + ""; + } } \ No newline at end of file From 067c0af3c298e24a787d3fbd14b5903b59cee0b1 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 2 Aug 2019 14:37:17 +0100 Subject: [PATCH 26/70] shortest word distance 1,2,3 done --- .../leetcode/arrays/ShortestWordDistance.java | 18 +++-- .../arrays/ShortestWordDistanceIII.java | 80 +++++++++++++++++++ .../leetcode/maps/ShortestWordDistanceII.java | 74 ++++++++++++++--- .../trees/ClosestBinarySearchTreeValue.java | 6 +- 4 files changed, 158 insertions(+), 20 deletions(-) create mode 100644 src/main/java/com/leetcode/arrays/ShortestWordDistanceIII.java diff --git a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java index 44e90d1a..fbe9706f 100644 --- a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java +++ b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java @@ -4,7 +4,7 @@ /** * Level: Easy - * Problem Link: + * Problem Link: https://leetcode.com/problems/shortest-word-distance/ * Problem Description: * Given a list of words and two words word1 and word2, return the shortest distance between these two words in the * list of words. @@ -34,18 +34,20 @@ public class ShortestWordDistance { * @return */ public static int findShortestDistance(String[] words, String word1, String word2) { - int startWord1 = Integer.MIN_VALUE; - int startWord2 = Integer.MAX_VALUE; + int indexWord1 = -1; + int indexWord2 = -1; int minDistance = Integer.MAX_VALUE; for (int i = 0; i < words.length; i++) { if (words[i].equals(word1)) { - startWord1 = i; + indexWord1 = i; } if (words[i].equals(word2)) { - startWord2 = i; + indexWord2 = i; + } + if (indexWord1 != -1 && indexWord2 != -1) { + minDistance = Math.min(minDistance, Math.abs(indexWord1 - indexWord2)); } - minDistance = Math.min(minDistance, Math.abs(startWord1 - startWord2)); } return minDistance; @@ -54,8 +56,12 @@ public static int findShortestDistance(String[] words, String word1, String word public static void main(String[] args) { assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, "practice", "coding")); + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "coding", "practice")); assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, "makes", "coding")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "perfect")); assertEquals(0, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, "perfect", "perfect")); assertEquals(0, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, diff --git a/src/main/java/com/leetcode/arrays/ShortestWordDistanceIII.java b/src/main/java/com/leetcode/arrays/ShortestWordDistanceIII.java new file mode 100644 index 00000000..0d404633 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/ShortestWordDistanceIII.java @@ -0,0 +1,80 @@ +package com.leetcode.arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/shortest-word-distance-iii/ + * Problem Description: + * This is a follow-up problem of {@link ShortestWordDistance}. The only difference is that now word1 could be the + * same as word2. + *

+ * Given a list of words and two words word1 and word2, return the shortest distance between these two words in the list. + * word1 and word2 may be the same and they represent two individual words in the list. + *

+ * For example, + * Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. + * Given word1 = “makes”, word2 = “coding”, return 1. + * Given word1 = "makes", word2 = "makes", return 3. + *

+ * Note: You may assume word1 and word2 are both in the list. If they are same then it's guaranteed that there are + * two occurrences of the same. + * + * @author rampatra + * @since 2019-07-31 + */ +public class ShortestWordDistanceIII { + + /** + * Time Complexity: + * Space Complexity: + * TODO + * + * @param words + * @param word1 + * @param word2 + * @return + */ + public static int findShortestDistance(String[] words, String word1, String word2) { + int indexWord1 = -1; + int indexWord2 = -1; + int minDistance = Integer.MAX_VALUE; + + for (int i = 0; i < words.length; i++) { + if (words[i].equals(word1)) { + // if both words are same and the first index is already set then do nothing + if (word1.equals(word2) && indexWord1 != -1) { + + } else { + indexWord1 = i; + } + } + if (words[i].equals(word2)) { + // if both words are same and i is same as first index then it implies its the + // first occurrence, skip and continue look for the second occurrence + if (word1.equals(word2) && i == indexWord1) { + continue; + } + indexWord2 = i; + } + if (indexWord1 != -1 && indexWord2 != -1) { + minDistance = Math.min(minDistance, Math.abs(indexWord1 - indexWord2)); + } + } + + return minDistance; + } + + public static void main(String[] args) { + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "makes")); + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "coding", "practice")); + assertEquals(3, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "practice", "coding")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "coding")); + assertEquals(1, findShortestDistance(new String[]{"practice", "makes", "perfect", "coding", "makes"}, + "makes", "perfect")); + } +} diff --git a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java index 6d5795c6..aed19c01 100644 --- a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java +++ b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java @@ -1,34 +1,82 @@ package com.leetcode.maps; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + /** * Level: Medium * Problem Link: https://leetcode.com/problems/shortest-word-distance-ii/ (premium) * Problem Description: - * This is a follow up of Shortest Word Distance. The only difference is now you are given the list of words and - * your method will be called repeatedly many times with different parameters. How would you optimize it? - *

* Design a class which receives a list of words in the constructor, and implements a method that takes two words - * word1 and word2 and return the shortest distance between these two words in the list. + * word1 and word2 and return the shortest distance between these two words in the list. Your method will be called + * repeatedly many times with different parameters. For a simpler variant, see {@link com.leetcode.arrays.ShortestWordDistance}. *

- * Example 1: + * Examples: * Assume that words = ["practice", "makes", "perfect", "coding", "makes"]. - * Given word1 = "coding”, word2 = "practice”, return 3. - * Given word1 = "makes", word2 = "coding", return 1. *

- * Note: You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. + * Input1: word1 = “coding”, word2 = “practice” + * Output1: 3 + *

+ * Input2: word1 = "makes", word2 = "coding" + * Output2: 1 *

- * Lastly, for a simpler variant, see {@link com.leetcode.arrays.ShortestWordDistance}. + * Note: You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. * * @author rampatra * @since 2019-07-31 */ public class ShortestWordDistanceII { - public static int findShortestDistance(String[] words, String word1, String word2) { - return -1; + private String[] words; + private Map> wordsToIndexesMap; + + ShortestWordDistanceII(String[] words) { + this.words = words; + this.wordsToIndexesMap = getWordsToIndexesMap(); } - public static void main(String[] args) { + public int findShortestDistance(String word1, String word2) { + return findShortestDistance(wordsToIndexesMap.get(word1), wordsToIndexesMap.get(word2)); + } + private int findShortestDistance(List indexes1, List indexes2) { + int minDistance = Integer.MAX_VALUE; + + for (int i = 0, j = 0; i < indexes1.size() && j < indexes2.size(); ) { + if (indexes1.get(i) <= indexes2.get(j)) { + minDistance = Math.min(minDistance, Math.abs(indexes1.get(i) - indexes2.get(j))); + i++; + } else if (indexes1.get(i) > indexes2.get(j)) { + minDistance = Math.min(minDistance, Math.abs(indexes1.get(i) - indexes2.get(j))); + j++; + } + } + + return minDistance; + } + + private Map> getWordsToIndexesMap() { + Map> wordsToIndexesMap = new HashMap<>(); + + for (int i = 0; i < words.length; i++) { + wordsToIndexesMap.putIfAbsent(words[i], new ArrayList<>()); + wordsToIndexesMap.get(words[i]).add(i); + } + return wordsToIndexesMap; + } + + public static void main(String[] args) { + ShortestWordDistanceII shortestWordDist = new ShortestWordDistanceII(new String[]{"practice", "makes", "perfect", "coding", "makes"}); + assertEquals(1, shortestWordDist.findShortestDistance("coding", "makes")); + assertEquals(1, shortestWordDist.findShortestDistance("perfect", "makes")); + assertEquals(1, shortestWordDist.findShortestDistance("practice", "makes")); + assertEquals(1, shortestWordDist.findShortestDistance("makes", "practice")); + assertEquals(3, shortestWordDist.findShortestDistance("coding", "practice")); + assertEquals(0, shortestWordDist.findShortestDistance("coding", "coding")); + assertEquals(0, shortestWordDist.findShortestDistance("makes", "makes")); } -} +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java index 80367748..db62d927 100644 --- a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java @@ -6,6 +6,11 @@ * Level: Easy * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value/ (premium) * Problem Description: + * Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target. + *

+ * Note: + * - Given target value is a floating point. + * - You are guaranteed to have only one unique value in the BST that is closest to the target. * * @author rampatra * @since 2019-07-31 @@ -13,7 +18,6 @@ public class ClosestBinarySearchTreeValue { /** - * * @param node * @param parentNode * @param val From 57caf4da0aa2a8cc15b13c194f3d7869cc3405ae Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sat, 3 Aug 2019 18:29:45 +0100 Subject: [PATCH 27/70] Added comments, runtime, etc. --- .../arrays/NestedListWeightSumII.java | 50 ++++---- .../leetcode/arrays/ShortestWordDistance.java | 5 +- .../dynamicprogramming/PaintHouse.java | 2 + .../leetcode/maps/ShortestWordDistanceII.java | 7 ++ .../trees/ClosestBinarySearchTreeValueII.java | 76 ++++++++++++ .../leetcode/trees/LeavesOfBinaryTree.java | 10 +- .../trees/SecondMinNodeInBinaryTree.java | 108 ++++++++++++++++++ 7 files changed, 226 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java create mode 100644 src/main/java/com/leetcode/trees/SecondMinNodeInBinaryTree.java diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java index 85448337..669bc734 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java @@ -28,30 +28,31 @@ public class NestedListWeightSumII { /** + * Time Complexity: + * Space Complexity: + * Runtime: 1 ms. + * * @param nestedList * @return */ - public static long nestedSum(List nestedList) { - long weightedSum = 0; - long unweightedSum = 0; - Queue queue = new LinkedList<>(); - - for (NestedInteger nestedInteger : nestedList) { - if (nestedInteger.isInteger()) { - unweightedSum += nestedInteger.getInteger(); - } else { - queue.addAll(nestedInteger.getList()); - while (!queue.isEmpty()) { - NestedInteger ni = queue.poll(); - if (ni.isInteger()) { - unweightedSum += ni.getInteger(); - } else { - nestedList.addAll(ni.getList()); - } + public static int nestedSum(List nestedList) { + int weightedSum = 0; + int unweightedSum = 0; + + while (!nestedList.isEmpty()) { + List nextLevel = new ArrayList<>(); + + for (NestedInteger ni : nestedList) { + if (ni.isInteger()) { + unweightedSum += ni.getInteger(); + } else { + nextLevel.addAll(ni.getList()); } - unweightedSum += unweightedSum; - weightedSum = unweightedSum; } + + unweightedSum += unweightedSum; // multiplication by repetitive addition + weightedSum = unweightedSum; + nestedList = nextLevel; } return weightedSum; @@ -62,19 +63,20 @@ public static void main(String[] args) { assertEquals(0, nestedSum(Collections.singletonList(new NestedInteger().add(new NestedInteger())))); + // TODO: fix the test cases + + // {2, {1,1}, {1,1}} NestedInteger ni = new NestedInteger(2); ni.add(new NestedInteger().add(new NestedInteger(1)).add(new NestedInteger(1))); ni.add(new NestedInteger().add(new NestedInteger(1)).add(new NestedInteger(1))); - assertEquals(10, nestedSum(Collections.singletonList(ni))); + assertEquals(6, nestedSum(Collections.singletonList(ni))); + // {1, {4, {6}}} ni = new NestedInteger(1); ni.add(new NestedInteger(4).add(new NestedInteger(6))); - assertEquals(27, nestedSum(Collections.singletonList(ni))); - - /*assertEquals(10, nestedSum(new Object[]{new Object[]{1, 1}, 2, new Object[]{1, 1}})); - assertEquals(27, nestedSum(new Object[]{1, new Object[]{4, new Object[]{6}}}));*/ + assertEquals(17, nestedSum(Collections.singletonList(ni))); } } diff --git a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java index fbe9706f..50b198cd 100644 --- a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java +++ b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java @@ -26,7 +26,7 @@ public class ShortestWordDistance { /** * Time Complexity: * Space Complexity: - * TODO + * Runtime: 1 ms. * * @param words * @param word1 @@ -41,8 +41,7 @@ public static int findShortestDistance(String[] words, String word1, String word for (int i = 0; i < words.length; i++) { if (words[i].equals(word1)) { indexWord1 = i; - } - if (words[i].equals(word2)) { + } else if (words[i].equals(word2)) { indexWord2 = i; } if (indexWord1 != -1 && indexWord2 != -1) { diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java index ae5db698..788ac5ee 100644 --- a/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java +++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java @@ -20,6 +20,8 @@ public class PaintHouse { /** + * Runtime: 1 ms. + * * @param costs of coloring the houses with red, blue, and green respectively. 1st row represents house 1, 2nd row * house 2 and so on * @return the minimum cost to paint all houses such that no two adjacent houses are of same color diff --git a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java index aed19c01..fe2e24c0 100644 --- a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java +++ b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java @@ -39,6 +39,13 @@ public class ShortestWordDistanceII { this.wordsToIndexesMap = getWordsToIndexesMap(); } + /** + * Runtime: 65 ms. + * + * @param word1 + * @param word2 + * @return + */ public int findShortestDistance(String word1, String word2) { return findShortestDistance(wordsToIndexesMap.get(word1), wordsToIndexesMap.get(word2)); } diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java new file mode 100644 index 00000000..953caf89 --- /dev/null +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java @@ -0,0 +1,76 @@ +package com.leetcode.trees; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value-ii/ (premium) + * Problem Description: + * + * + * @author rampatra + * @since 2019-07-31 + */ +public class ClosestBinarySearchTreeValueII { + + /** + * @param node + * @param parentNode + * @param val + * @param diff + * @return + */ + public static TreeNode findNodeWithClosestValue(TreeNode node, TreeNode parentNode, int val, int diff) { + return null; + } + + public static void main(String[] args) { + + /* + BST looks like: + + 9 + / \ + 7 13 + / \ \ + 5 8 20 + / \ + 2 6 + */ + TreeNode root = new TreeNode(9); + root.left = new TreeNode(7); + root.right = new TreeNode(13); + root.left.left = new TreeNode(5); + root.left.right = new TreeNode(8); + root.left.left.left = new TreeNode(2); + root.left.left.right = new TreeNode(6); + root.right.right = new TreeNode(20); + + assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); + assertEquals(13, findNodeWithClosestValue(root, root, 13, Integer.MAX_VALUE).val); + assertEquals(9, findNodeWithClosestValue(root, root, 9, Integer.MAX_VALUE).val); + assertEquals(2, findNodeWithClosestValue(root, root, 2, Integer.MAX_VALUE).val); + assertEquals(2, findNodeWithClosestValue(root, root, 1, Integer.MAX_VALUE).val); + assertEquals(6, findNodeWithClosestValue(root, root, 6, Integer.MAX_VALUE).val); + assertEquals(13, findNodeWithClosestValue(root, root, 11, Integer.MAX_VALUE).val); // tie b/w 9 and 13 + + /* + BST looks like: + + 9 + / \ + 7 13 + / \ / \ + 5 8 13 20 + */ + root = new TreeNode(9); + root.left = new TreeNode(7); + root.right = new TreeNode(13); + root.left.left = new TreeNode(5); + root.left.right = new TreeNode(8); + root.right.left = new TreeNode(13); + root.right.right = new TreeNode(20); + + assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); + } +} diff --git a/src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java b/src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java index 8dcd0c1f..6ca15e22 100644 --- a/src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java +++ b/src/main/java/com/leetcode/trees/LeavesOfBinaryTree.java @@ -45,18 +45,18 @@ public class LeavesOfBinaryTree { * the node into the list indexed by their heights. * Time Complexity: * Space Complexity: - * Runtime: . + * Runtime: 1 ms. * * @param root * @return */ - public static List> findLeavesOfBinaryTree(TreeNode root) { - List> levels = new ArrayList<>(); + public static List> findLeavesOfBinaryTree(TreeNode root) { + List> levels = new ArrayList<>(); findLeavesOfBinaryTree(root, levels); return levels; } - private static int findLeavesOfBinaryTree(TreeNode root, List> levels) { + private static int findLeavesOfBinaryTree(TreeNode root, List> levels) { if (root == null) return -1; int leftHeight = findLeavesOfBinaryTree(root.left, levels); @@ -66,7 +66,7 @@ private static int findLeavesOfBinaryTree(TreeNode root, List> le if (height >= levels.size()) { levels.add(height, new ArrayList<>()); } - levels.get(height).add(root); + levels.get(height).add(root.val); return height; } diff --git a/src/main/java/com/leetcode/trees/SecondMinNodeInBinaryTree.java b/src/main/java/com/leetcode/trees/SecondMinNodeInBinaryTree.java new file mode 100644 index 00000000..a8cddf74 --- /dev/null +++ b/src/main/java/com/leetcode/trees/SecondMinNodeInBinaryTree.java @@ -0,0 +1,108 @@ +package com.leetcode.trees; + +import java.util.Stack; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/ + * Problem Description: + * Given a non-empty special binary tree consisting of nodes with the non-negative value, where each node in this + * tree has exactly two or zero sub-node. If the node has two sub-nodes, then this node's value is the smaller value + * among its two sub-nodes. More formally, the property root.val = min(root.left.val, root.right.val) always holds. + * + * Given such a binary tree, you need to output the second minimum value in the set made of all the nodes' value in + * the whole tree. + * + * If no such second minimum value exists, output -1 instead. + * + * Example 1: + * Input: + * 2 + * / \ + * 2 5 + * / \ + * 5 7 + * + * Output: 5 + * Explanation: The smallest value is 2, the second smallest value is 5. + * + * + * Example 2: + * Input: + * 2 + * / \ + * 2 2 + * + * Output: -1 + * Explanation: The smallest value is 2, but there isn't any second smallest value. + * + * @author rampatra + * @since 2019-08-03 + */ +public class SecondMinNodeInBinaryTree { + + /** + * Time Complexity: O(n) + * Space Complexity: O(n) + * Runtime: 1 ms. + * @param root + * @return + */ + public static int findSecondMinimumValueIterative(TreeNode root) { + if (root == null || (root.left == null && root.right == null)) return -1; + + int min = root.val; + long secondMin = Long.MAX_VALUE; + + Stack stack = new Stack<>(); + stack.push(root); + + while (!stack.empty()) { + TreeNode node = stack.pop(); + if (node == null) continue; + + if (node.val > min && node.val < secondMin) { + secondMin = node.val; + } + stack.push(node.left); + stack.push(node.right); + } + + return secondMin == Long.MAX_VALUE ? -1 : (int) secondMin; + } + + + /** + * Time Complexity: + * Space Complexity: + * Runtime: 0 ms. + * + * @param root + * @return + */ + public static int findSecondMinimumValue(TreeNode root) { + // passing a long as secondMin because TreeNode can have Integer.MAX_VALUE as its value + long ans = findSecondMinimumValue(root, root.val, Long.MAX_VALUE); + return ans == Long.MAX_VALUE ? -1 : (int) ans; + } + + private static long findSecondMinimumValue(TreeNode root, int min, long secondMin) { + if (root == null) return Long.MAX_VALUE; + + if (root.val > min && root.val < secondMin) { + return root.val; + } else { + return Math.min(findSecondMinimumValue(root.left, min, secondMin), + findSecondMinimumValue(root.right, min, secondMin)); + } + } + + public static void main(String[] args) { + System.out.println((int) 2147483647L); + System.out.println(Integer.MAX_VALUE); + // TODO: A function called buildTree which would take an array like [1,1,3,1,1,3,4,3,1,1,1,3,8,4,8,3,3,1,6,2,1] + // and return a Binary Tree + //assertEquals(2, findSecondMinimumValue(buildTree(new int[]{1,1,3,1,1,3,4,3,1,1,1,3,8,4,8,3,3,1,6,2,1}))); + //assertEquals(2147483647, findSecondMinimumValue(buildTree(new int[]{2,2,2147483647}))); + } +} From d7183ac81db5f31786f7e520a40fdda81f4e3d19 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sat, 3 Aug 2019 21:25:51 +0100 Subject: [PATCH 28/70] TwoSummIII done --- .../arrays/NestedListWeightSumII.java | 1 - .../java/com/leetcode/maps/TwoSumIII.java | 78 +++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/leetcode/maps/TwoSumIII.java diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java index 669bc734..1cb40945 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java @@ -64,7 +64,6 @@ public static void main(String[] args) { assertEquals(0, nestedSum(Collections.singletonList(new NestedInteger().add(new NestedInteger())))); // TODO: fix the test cases - // {2, {1,1}, {1,1}} NestedInteger ni = new NestedInteger(2); ni.add(new NestedInteger().add(new NestedInteger(1)).add(new NestedInteger(1))); diff --git a/src/main/java/com/leetcode/maps/TwoSumIII.java b/src/main/java/com/leetcode/maps/TwoSumIII.java new file mode 100644 index 00000000..22f0748f --- /dev/null +++ b/src/main/java/com/leetcode/maps/TwoSumIII.java @@ -0,0 +1,78 @@ +package com.leetcode.maps; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Level: Easy + * Problem Link: https://leetcode.com/problems/two-sum-iii-data-structure-design/ + * Problem Description: + * Design and implement a TwoSum class. It should support the following operations: add and find. + *

+ * add - Add the number to an internal data structure. + * find - Find if there exists any pair of numbers which sum is equal to the value. + *

+ * Example 1: + * add(1); add(3); add(5); + * find(4) -> true + * find(7) -> false + *

+ * Example 2: + * add(3); add(1); add(2); + * find(3) -> true + * find(6) -> false + * + * @author rampatra + * @since 2019-08-03 + */ +public class TwoSumIII { + + Map numCount; + + /** + * Initialize your data structure here. + */ + public TwoSumIII() { + this.numCount = new HashMap<>(); + } + + /** + * Add the number to an internal data structure.. + */ + public void add(int number) { + if (numCount.containsKey(number)) { + numCount.put(number, 2); + } else { + numCount.put(number, 1); + } + } + + /** + * Find if there exists any pair of numbers which sum is equal to the value. + */ + public boolean find(int value) { + for (Map.Entry entry : numCount.entrySet()) { + int num1 = entry.getKey(); + int num2 = value - num1; + if ((num2 == num1 && entry.getValue() == 2) || (num1 != num2 && numCount.containsKey(num2))) { + return true; + } + } + return false; + } + + /** + * Runtime: 115 ms. + * + * @param args + */ + public static void main(String[] args) { + TwoSumIII twoSumIII = new TwoSumIII(); + twoSumIII.add(0); + twoSumIII.add(-1); + twoSumIII.add(1); + assertTrue(twoSumIII.find(0)); + } +} \ No newline at end of file From 1908338f1f4c219890b49d2cc22f0777c7a296cb Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 4 Aug 2019 12:54:08 +0100 Subject: [PATCH 29/70] binary tree upside down: done --- .../leetcode/trees/BinaryTreeUpsideDown.java | 207 ++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 src/main/java/com/leetcode/trees/BinaryTreeUpsideDown.java diff --git a/src/main/java/com/leetcode/trees/BinaryTreeUpsideDown.java b/src/main/java/com/leetcode/trees/BinaryTreeUpsideDown.java new file mode 100644 index 00000000..aa43bf50 --- /dev/null +++ b/src/main/java/com/leetcode/trees/BinaryTreeUpsideDown.java @@ -0,0 +1,207 @@ +package com.leetcode.trees; + +import java.util.Stack; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/binary-tree-upside-down/ + * Problem Description: + * Given a binary tree where all the right nodes are either leaf nodes with a sibling (a left node that shares the + * same parent node) or empty, flip it upside down and turn it into a tree where the original right nodes turned into + * left leaf nodes. Return the new root. + * + * Example: + * Input: [1,2,3,4,5] + * + * 1 + * / \ + * 2 3 + * / \ + * 4 5 + * + * Output: return the root of the binary tree [4,5,2,#,#,3,1] + * + * 4 + * / \ + * 5 2 + * / \ + * 3 1 + * + * Clarification: + * Confused what [4,5,2,#,#,3,1] means? Read more below on how binary tree is serialized on OJ. The serialization of + * a binary tree follows a level order traversal, where '#' signifies a path terminator where no node exists below. + * + * Here's an example: + * + * 1 + * / \ + * 2 3 + * / + * 4 + * \ + * 5 + * + * The above binary tree is serialized as [1,2,3,#,#,4,#,#,5]. + * + * @author rampatra + * @since 2019-08-04 + */ +public class BinaryTreeUpsideDown { + + /** + * The solution is simple, every node (except the root) on the left of the tree would have its parent's right child + * as it's left child and parent as its right child. That's all you have to do to flip the tree upside down. + * + * Time Complexity: O(h) + * Space Complexity: O(h) + * where, + * h = height of the tree + * + * Runtime: 1 ms. + * + * @param root + * @return + */ + public static TreeNode upsideDownBinaryTreeUsingStack(TreeNode root) { + if (root == null) return null; + + TreeNode curr = root; + TreeNode currParent; + TreeNode newRoot = null; + + // using stack to keep track of the parent node + Stack stack = new Stack<>(); + + while (curr != null) { + stack.add(curr); + curr = curr.left; + } + + while (!stack.empty()) { + curr = stack.pop(); + currParent = stack.empty() ? null : stack.peek(); + + if (newRoot == null) newRoot = curr; + + if (currParent != null) { + curr.left = currParent.right; + curr.right = currParent; + } else { + curr.left = null; + curr.right = null; + } + } + + return newRoot; + } + + /** + * The solution is simple, every node (except the root) on the left of the tree would have its parent's right child + * as it's left child and parent as its right child. That's all you have to do to flip the tree upside down. + * + * Time Complexity: O(h) + * Space Complexity: O(h) + * where, + * h = height of the tree + * + * Runtime: 0 ms. + * + * @param node + * @return + */ + public static TreeNode upsideDownBinaryTree(TreeNode node) { + if (node == null || node.left == null) return node; + + // go to the last node on the extreme left branch + TreeNode newRoot = upsideDownBinaryTree(node.left); + + // do the node changes as you backtrack + node.left.left = node.right; + node.left.right = node; + + // clean up + node.left = null; + node.right = null; + + return newRoot; + } + + public static void main(String[] args) { + /* + Binary Tree + + 1 + / \ + 2 3 + / \ + 4 5 + */ + TreeNode tree = new TreeNode(1); + tree.left = new TreeNode(2); + tree.right = new TreeNode(3); + tree.left.left = new TreeNode(4); + tree.left.right = new TreeNode(5); + + /* + Upside Down Binary Tree + + 4 + / \ + 5 2 + / \ + 3 1 + */ + TreeNode upsideDownTree = upsideDownBinaryTreeUsingStack(tree); + assertEquals(4, upsideDownTree.val); + assertEquals(5, upsideDownTree.left.val); + assertEquals(2, upsideDownTree.right.val); + assertEquals(1, upsideDownTree.right.right.val); + assertEquals(3, upsideDownTree.right.left.val); + assertNull(upsideDownTree.right.right.left); + assertNull(upsideDownTree.right.right.right); + + + + /****************************** + * + * Test for the recursive method + * + ******************************/ + + /* + Binary Tree + + 1 + / \ + 2 3 + / \ + 4 5 + */ + tree = new TreeNode(1); + tree.left = new TreeNode(2); + tree.right = new TreeNode(3); + tree.left.left = new TreeNode(4); + tree.left.right = new TreeNode(5); + + /* + Upside Down Binary Tree + + 4 + / \ + 5 2 + / \ + 3 1 + */ + upsideDownTree = upsideDownBinaryTree(tree); + assertEquals(4, upsideDownTree.val); + assertEquals(5, upsideDownTree.left.val); + assertEquals(2, upsideDownTree.right.val); + assertEquals(1, upsideDownTree.right.right.val); + assertEquals(3, upsideDownTree.right.left.val); + assertNull(upsideDownTree.right.right.right); + assertNull(upsideDownTree.right.right.left); + } +} \ No newline at end of file From 2dd2b814d5389b800cd9b5e4d493fba2d324febf Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 4 Aug 2019 12:55:41 +0100 Subject: [PATCH 30/70] minor refactorings --- src/main/java/com/leetcode/arrays/NestedListWeightSum.java | 2 +- src/main/java/com/leetcode/arrays/NestedListWeightSumII.java | 2 +- src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java | 2 +- src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java | 2 +- src/main/java/com/leetcode/maps/ShortestWordDistanceII.java | 2 +- .../java/com/leetcode/trees/ClosestBinarySearchTreeValue.java | 2 +- .../java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSum.java b/src/main/java/com/leetcode/arrays/NestedListWeightSum.java index b59a51ee..4886c445 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSum.java +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSum.java @@ -4,7 +4,7 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/nested-list-weight-sum/ (premium) + * Problem Link: https://leetcode.com/problems/nested-list-weight-sum/ * Problem Description: * Given a nested list of integers, return the sum of all integers in the list weighted by their depth. Each element * is either an integer, or a list – whose elements may also be integers or other lists. diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java index 1cb40945..379c8f5e 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java +++ b/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java @@ -6,7 +6,7 @@ /** * Level: Medium - * Problem Link: https://leetcode.com/problems/nested-list-weight-sum-ii/ (premium) + * Problem Link: https://leetcode.com/problems/nested-list-weight-sum-ii/ * Problem Description: * Given a nested list of integers, return the sum of all integers in the list weighted by their depth. Each element * is either an integer, or a list – whose elements may also be integers or other lists. diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java index 788ac5ee..5692b0d8 100644 --- a/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java +++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouse.java @@ -2,7 +2,7 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/paint-house/ (premium) + * Problem Link: https://leetcode.com/problems/paint-house/ * Problem Description: * There are a row of n houses, each house can be painted with one of the three colors: red, blue or green. The cost * of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent diff --git a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java index 1c51ee68..431ce612 100644 --- a/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java +++ b/src/main/java/com/leetcode/dynamicprogramming/PaintHouseII.java @@ -4,7 +4,7 @@ /** * Level: Hard - * Problem Link: https://leetcode.com/problems/paint-house-ii/ (premium) + * Problem Link: https://leetcode.com/problems/paint-house-ii/ * Problem Description: * There are a row of n houses, each house can be painted with one of the m colors. * The cost of painting each house with a certain color is different. diff --git a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java index fe2e24c0..ecb6c9b9 100644 --- a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java +++ b/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java @@ -9,7 +9,7 @@ /** * Level: Medium - * Problem Link: https://leetcode.com/problems/shortest-word-distance-ii/ (premium) + * Problem Link: https://leetcode.com/problems/shortest-word-distance-ii/ * Problem Description: * Design a class which receives a list of words in the constructor, and implements a method that takes two words * word1 and word2 and return the shortest distance between these two words in the list. Your method will be called diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java index db62d927..83b87a9f 100644 --- a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java @@ -4,7 +4,7 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value/ (premium) + * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value/ * Problem Description: * Given a non-empty binary search tree and a target value, find the value in the BST that is closest to the target. *

diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java index 953caf89..4f5cbe71 100644 --- a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java @@ -4,7 +4,7 @@ /** * Level: Hard - * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value-ii/ (premium) + * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value-ii/ * Problem Description: * * From 7d9dec6de6a972ee6bb60b1e379772d167ecb1f0 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 4 Aug 2019 15:17:51 +0100 Subject: [PATCH 31/70] closest bst value: done --- .../trees/ClosestBinarySearchTreeValue.java | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java index 83b87a9f..ca6d94b7 100644 --- a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValue.java @@ -18,21 +18,29 @@ public class ClosestBinarySearchTreeValue { /** - * @param node - * @param parentNode - * @param val - * @param diff + * Runtime: 0 ms. + * + * @param root + * @param target * @return */ - public static TreeNode findNodeWithClosestValue(TreeNode node, TreeNode parentNode, int val, int diff) { - if (node == null) return parentNode; + public static int closestValue(TreeNode root, double target) { + if (root == null) return -1; - if (Math.abs(node.val - val) > diff) return parentNode; + return closestValue(root, root, target); + } + + private static int closestValue(TreeNode node, TreeNode closestNode, double val) { + if (node == null) return closestNode.val; + + if (Math.abs(node.val - val) < Math.abs(closestNode.val - val)) { + closestNode = node; + } if (node.val > val) { - return findNodeWithClosestValue(node.left, node, val, Math.abs(node.val - val)); + return closestValue(node.left, closestNode, val); } else { - return findNodeWithClosestValue(node.right, node, val, Math.abs(node.val - val)); + return closestValue(node.right, closestNode, val); } } @@ -54,17 +62,17 @@ public static void main(String[] args) { root.right = new TreeNode(13); root.left.left = new TreeNode(5); root.left.right = new TreeNode(8); - root.left.left.left = new TreeNode(2); root.left.left.right = new TreeNode(6); + root.left.left.left = new TreeNode(2); root.right.right = new TreeNode(20); - assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); - assertEquals(13, findNodeWithClosestValue(root, root, 13, Integer.MAX_VALUE).val); - assertEquals(9, findNodeWithClosestValue(root, root, 9, Integer.MAX_VALUE).val); - assertEquals(2, findNodeWithClosestValue(root, root, 2, Integer.MAX_VALUE).val); - assertEquals(2, findNodeWithClosestValue(root, root, 1, Integer.MAX_VALUE).val); - assertEquals(6, findNodeWithClosestValue(root, root, 6, Integer.MAX_VALUE).val); - assertEquals(13, findNodeWithClosestValue(root, root, 11, Integer.MAX_VALUE).val); // tie b/w 9 and 13 + assertEquals(13, closestValue(root, 15)); + assertEquals(13, closestValue(root, 13)); + assertEquals(9, closestValue(root, 9)); + assertEquals(2, closestValue(root, 2)); + assertEquals(2, closestValue(root, 1)); + assertEquals(6, closestValue(root, 6)); + assertEquals(13, closestValue(root, 11)); // tie b/w 9 and 13 /* BST looks like: @@ -83,6 +91,20 @@ public static void main(String[] args) { root.right.left = new TreeNode(13); root.right.right = new TreeNode(20); - assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); + assertEquals(13, closestValue(root, 15)); + + /* + BST looks like: + + 1500000000 + / + / + / + 1400000000 + */ + root = new TreeNode(1500000000); + root.left = new TreeNode(1400000000); + + assertEquals(1400000000, closestValue(root, -1500000000.0)); } } From cad93221a015af5453aafe18c3ad374d0eba0ffb Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 4 Aug 2019 21:49:16 +0100 Subject: [PATCH 32/70] hit counter done --- .../com/leetcode/design/DesignHitCounter.java | 117 ++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/main/java/com/leetcode/design/DesignHitCounter.java diff --git a/src/main/java/com/leetcode/design/DesignHitCounter.java b/src/main/java/com/leetcode/design/DesignHitCounter.java new file mode 100644 index 00000000..62133196 --- /dev/null +++ b/src/main/java/com/leetcode/design/DesignHitCounter.java @@ -0,0 +1,117 @@ +package com.leetcode.design; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/design-hit-counter/ + * Problem Description: + * Design a hit counter which counts the number of hits received in the past 5 minutes. + * + * Each function accepts a timestamp parameter (in seconds granularity) and you may assume that calls are being made + * to the system in chronological order (ie, the timestamp is monotonically increasing). You may assume that the + * earliest timestamp starts at 1. + * + * It is possible that several hits arrive roughly at the same time. + * + * Example: + * + * HitCounter counter = new HitCounter(); + * + * // hit at timestamp 1. + * counter.hit(1); + * + * // hit at timestamp 2. + * counter.hit(2); + * + * // hit at timestamp 3. + * counter.hit(3); + * + * // get hits at timestamp 4, should return 3. + * counter.getHits(4); + * + * // hit at timestamp 300. + * counter.hit(300); + * + * // get hits at timestamp 300, should return 4. + * counter.getHits(300); + * + * // get hits at timestamp 301, should return 3. + * counter.getHits(301); + * + * Follow up: + * What if the number of hits per second could be very large? Does your design scale? + * + * Runtime: 42 ms (better than ~98%). + * + * @author rampatra + * @since 2019-08-04 + */ +public class DesignHitCounter { + + private int[] timestamps; + private int[] hits; + + /** + * Initialize your data structure here. + */ + public DesignHitCounter() { + this.timestamps = new int[300]; + this.hits = new int[300]; + } + + /** + * Record a hit. + * + * @param timestamp - The current timestamp (in seconds granularity). + */ + public void hit(int timestamp) { + int bucket = timestamp % 300; + if (timestamps[bucket] == timestamp) { + hits[bucket]++; + } else { + timestamps[bucket] = timestamp; + hits[bucket] = 1; + } + } + + /** + * Return the number of hits in the past 5 minutes. + * + * @param timestamp - The current timestamp (in seconds granularity). + */ + public int getHits(int timestamp) { + int totalHits = 0; + for (int i = 0; i < 300; i++) { + if (timestamp - 300 < timestamps[i]) { + totalHits += hits[i]; + } + } + return totalHits; + } + + public static void main(String[] args) { + DesignHitCounter counter = new DesignHitCounter(); + + // hit at timestamp 1. + counter.hit(1); + + // hit at timestamp 2. + counter.hit(2); + + // hit at timestamp 3. + counter.hit(3); + + // get hits at timestamp 4, should return 3. + assertEquals(3, counter.getHits(4)); + + // hit at timestamp 300. + counter.hit(300); + + // get hits at timestamp 300, should return 4. + assertEquals(4, counter.getHits(300)); + + // get hits at timestamp 301, should return 3. + assertEquals(3, counter.getHits(301)); + } +} From c386fbe8fcd237b695e9734ba29b01cfebbbd299 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 5 Aug 2019 15:28:00 +0100 Subject: [PATCH 33/70] find celebrity: done --- .../com/leetcode/arrays/FindTheCelebrity.java | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 src/main/java/com/leetcode/arrays/FindTheCelebrity.java diff --git a/src/main/java/com/leetcode/arrays/FindTheCelebrity.java b/src/main/java/com/leetcode/arrays/FindTheCelebrity.java new file mode 100644 index 00000000..1b15d996 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/FindTheCelebrity.java @@ -0,0 +1,105 @@ +package com.leetcode.arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/find-the-celebrity/ + * Problem Description: + * Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. + * The definition of a celebrity is that all the other n - 1 people know him/her but he/she does not know any of them. + * + * Now you want to find out who the celebrity is or verify that there is not one. The only thing you are allowed to do + * is to ask questions like: "Hi, A. Do you know B?" to get information of whether A knows B. You need to find out the + * celebrity (or verify there is not one) by asking as few questions as possible (in the asymptotic sense). + * + * You are given a helper function bool knows(a, b) which tells you whether A knows B. Implement a + * function int findCelebrity(n). There will be exactly one celebrity if he/she is in the party. Return the celebrity's + * label if there is a celebrity in the party. If there is no celebrity, return -1. + * + * Example 1: + * + * Input: graph = [ + * [1,1,0], + * [0,1,0], + * [1,1,1] + * ] + * Output: 1 + * Explanation: There are three persons labeled with 0, 1 and 2. graph[i][j] = 1 means person i knows person j, otherwise + * graph[i][j] = 0 means person i does not know person j. The celebrity is the person labeled as 1 because both 0 and 2 + * know him but 1 does not know anybody. + * + * + * Example 2: + * + * Input: graph = [ + * [1,0,1], + * [1,1,0], + * [0,1,1] + * ] + * Output: -1 + * Explanation: There is no celebrity. + * + * + * Note: The directed graph is represented as an adjacency matrix, which is an n x n matrix where a[i][j] = 1 means + * person i knows person j while a[i][j] = 0 means the contrary. Remember that you won't have direct access to the + * adjacency matrix. + * + * @author rampatra + * @since 2019-08-04 + */ +public class FindTheCelebrity { + + private int[][] knowsMatrix; + + FindTheCelebrity(int[][] knowsMatrix) { + this.knowsMatrix = knowsMatrix; + } + + public boolean knows(int a, int b) { + return knowsMatrix[a][b] == 1; + } + + /** + * Time Complexity: O(n) + * Space Complexity: O(1) + * Runtime: 6 ms. + * + * @param n + * @return + */ + public int findCelebrity(int n) { + int celebrityIndex = 0; + + for (int i = 1; i < n; i++) { + // if a person doesn't know another person then he maybe a celebrity + if (!knows(i, celebrityIndex)) { + celebrityIndex = i; + } + } + + for (int i = 0; i < n; i++) { + // verify whether the celebrity only knows himself and all other people know the celebrity + if ((knows(celebrityIndex, i) && i != celebrityIndex) || !knows(i, celebrityIndex)) { + return -1; + } + } + + return celebrityIndex; + } + + public static void main(String[] args) { + FindTheCelebrity findTheCelebrity = new FindTheCelebrity(new int[][]{ + {1, 1, 0}, + {0, 1, 0}, + {1, 1, 1}}); + + assertEquals(1, findTheCelebrity.findCelebrity(3)); + + findTheCelebrity = new FindTheCelebrity(new int[][]{ + {1, 0}, + {0, 1}}); + + assertEquals(-1, findTheCelebrity.findCelebrity(2)); + } +} From 7b99ea49d1c8c4a2754fe0a7218af68641cfe48e Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 7 Aug 2019 10:19:18 +0100 Subject: [PATCH 34/70] Graph Valid Tree: done --- .../com/leetcode/graphs/GraphValidTree.java | 131 ++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 src/main/java/com/leetcode/graphs/GraphValidTree.java diff --git a/src/main/java/com/leetcode/graphs/GraphValidTree.java b/src/main/java/com/leetcode/graphs/GraphValidTree.java new file mode 100644 index 00000000..15950143 --- /dev/null +++ b/src/main/java/com/leetcode/graphs/GraphValidTree.java @@ -0,0 +1,131 @@ +package com.leetcode.graphs; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/graph-valid-tree/ + * Problem Description: + * Given n nodes labeled from 0 to n-1 and a list of undirected edges (each edge is a pair of nodes), write a function + * to check whether these edges make up a valid tree. + *

+ * Example 1: + * Input: n = 5, and edges = [[0,1], [0,2], [0,3], [1,4]] + * Output: true + *

+ * Example 2: + * Input: n = 5, and edges = [[0,1], [1,2], [2,3], [1,3], [1,4]] + * Output: false + *

+ * Note: you can assume that no duplicate edges will appear in edges. Since all edges are undirected, [0,1] is the + * same as [1,0] and thus will not appear together in edges. + * + * @author rampatra + * @since 2019-08-05 + */ +public class GraphValidTree { + + /** + * + * @param n + * @param edges + * @return + */ + public static boolean isValidTree(int n, int[][] edges) { + List> adjacencyList = new ArrayList<>(n); + + for (int i = 0; i < n; i++) { + adjacencyList.add(new ArrayList<>()); + } + + for (int i = 0; i < edges.length; i++) { + adjacencyList.get(edges[i][0]).add(edges[i][1]); + } + + boolean[] visited = new boolean[n]; + + if (hasCycle(adjacencyList, 0, -1, visited)) { + return false; + } + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + return false; + } + } + + return true; + } + + private static boolean hasCycle(List> adjacencyList, int node1, int exclude, boolean[] visited) { + visited[node1] = true; + + for (int i = 0; i < adjacencyList.get(node1).size(); i++) { + int node2 = adjacencyList.get(node1).get(i); + + if ((visited[node2] && exclude != node2) || (!visited[node2] && hasCycle(adjacencyList, node2, node1, visited))) { + return true; + } + } + + return false; + } + + + /** + * Union-find algorithm: We keep all connected nodes in one set in the union operation and in find operation we + * check whether two nodes belong to the same set. If yes then there's a cycle and if not then no cycle. + * + * Good articles on union-find: + * - https://www.hackerearth.com/practice/notes/disjoint-set-union-union-find/ + * - https://www.youtube.com/watch?v=wU6udHRIkcc + * + * @param n + * @param edges + * @return + */ + public static boolean isValidTreeUsingUnionFind(int n, int[][] edges) { + int[] roots = new int[n]; + + for (int i = 0; i < n; i++) { + roots[i] = i; + } + + for (int i = 0; i < edges.length; i++) { + // find operation + if (roots[edges[i][0]] == roots[edges[i][1]]) { + return false; + } + // union operation + roots[edges[i][1]] = findRoot(roots, roots[edges[i][0]]); // note: we can optimize this even further by + // considering size of each side and then join the side with smaller size to the one with a larger size (weighted union). + // We can use another array called size to keep count of the size or we can use the same root array with + // negative values, i.e, negative resembles that the node is pointing to itself and the number will represent + // the size. For example, roots = [-2, -1, -1, 0] means that node 3 is pointing to node 0 and node 0 is pointing + // to itself and is has 2 nodes under it including itself. + } + + return edges.length == n - 1; + } + + private static int findRoot(int[] roots, int node) { + while (roots[node] != node) { + node = roots[node]; + } + return node; + } + + public static void main(String[] args) { + assertTrue(isValidTree(5, new int[][]{{0, 1}, {0, 2}, {0, 3}, {1, 4}})); + assertFalse(isValidTree(5, new int[][]{{0, 1}, {1, 2}, {2, 3}, {1, 3}, {1, 4}})); + assertFalse(isValidTree(3, new int[][]{{0, 1}, {1, 2}, {2, 0}})); + + assertTrue(isValidTreeUsingUnionFind(5, new int[][]{{0, 1}, {0, 2}, {0, 3}, {1, 4}})); + assertFalse(isValidTreeUsingUnionFind(5, new int[][]{{0, 1}, {1, 2}, {2, 3}, {1, 3}, {1, 4}})); + assertFalse(isValidTreeUsingUnionFind(3, new int[][]{{0, 1}, {1, 2}, {2, 0}})); + } +} \ No newline at end of file From 5d20974750f7df8fd41a7d7bc8e6c91ecf675d7f Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 7 Aug 2019 20:48:03 +0100 Subject: [PATCH 35/70] No of Islands done --- .../com/leetcode/arrays/NumberOfIslands.java | 107 ++++++++++++++++++ .../leetcode/arrays/ValidTriangleNumber.java | 47 ++++++++ 2 files changed, 154 insertions(+) create mode 100644 src/main/java/com/leetcode/arrays/NumberOfIslands.java create mode 100644 src/main/java/com/leetcode/arrays/ValidTriangleNumber.java diff --git a/src/main/java/com/leetcode/arrays/NumberOfIslands.java b/src/main/java/com/leetcode/arrays/NumberOfIslands.java new file mode 100644 index 00000000..04ac6831 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/NumberOfIslands.java @@ -0,0 +1,107 @@ +package com.leetcode.arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/number-of-islands/ + * Description: + * Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surrounded by water + * and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid + * are all surrounded by water. + *

+ * Example 1: + * Input: + * 11110 + * 11010 + * 11000 + * 00000 + * Output: 1 + *

+ * Example 2: + * Input: + * 11000 + * 11000 + * 00100 + * 00011 + * Output: 3 + * + * @author rampatra + * @since 2019-08-07 + */ +public class NumberOfIslands { + + /** + * The idea is simple and straightforward. Once we encounter land ('1' in grid) we drown the island or change the + * neighboring '1's to '0's. Therefore, the number of '1's we encounter, we can say that we have that many islands. + *

+ * Time Complexity: O(n) + * Space Complexity: O(n) + * Runtime: 1 ms. + * + * @param grid + * @return + */ + public static int numIslands(char[][] grid) { + int count = 0; + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == '1') { + drownTheIsland(grid, i, j); + count++; + } + } + } + + return count; + } + + private static void drownTheIsland(char[][] grid, int i, int j) { + if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length || grid[i][j] == '0') { + return; + } + + grid[i][j] = '0'; + + drownTheIsland(grid, i, j + 1); + drownTheIsland(grid, i, j - 1); + drownTheIsland(grid, i + 1, j); + drownTheIsland(grid, i - 1, j); + } + + public static void main(String[] args) { + assertEquals(1, numIslands(new char[][]{ + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '0', '0'} + })); + + assertEquals(2, numIslands(new char[][]{ + {'1', '1', '1', '1', '0'}, + {'1', '1', '0', '1', '0'}, + {'1', '1', '0', '0', '0'}, + {'0', '0', '0', '1', '0'} + })); + + assertEquals(1, numIslands(new char[][]{ + {'1', '1', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '1', '1', '1', '1'}, + {'1', '1', '1', '1', '1'} + })); + + assertEquals(1, numIslands(new char[][]{ + {'1'} + })); + + assertEquals(0, numIslands(new char[][]{ + {'0'} + })); + + assertEquals(0, numIslands(new char[][]{ + {} + })); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java b/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java new file mode 100644 index 00000000..bab45ded --- /dev/null +++ b/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java @@ -0,0 +1,47 @@ +package com.leetcode.arrays; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Problem Link: https://leetcode.com/problems/valid-triangle-number/ + * Problem Description: + * Given an array consists of non-negative integers, your task is to count the number of triplets chosen from the array + * that can make triangles if we take them as side lengths of a triangle. + *

+ * Example 1: + * Input: [2,2,3,4] + * Output: 3 + * Explanation: + * Valid combinations are: + * 2,3,4 (using the first 2) + * 2,3,4 (using the second 2) + * 2,2,3 + *

+ * Note: + * The length of the given array won't exceed 1000. + * The integers in the given array are in the range of [0, 1000]. + * + * @author rampatra + * @since 2019-08-07 + */ +public class ValidTriangleNumber { + + public static int triangleNumber(int[] nums) { + int l = 0; + int r = nums.length - 1; + int noOfTriangles = 0; + + Arrays.sort(nums); + + // todo + + return noOfTriangles; + } + + public static void main(String[] args) { + assertEquals(3, triangleNumber(new int[]{2, 2, 3, 4})); + } +} From 613bc46a82485155b2d3ccf4e7ca46c8fd78d699 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 9 Aug 2019 16:01:48 +0100 Subject: [PATCH 36/70] valid triangle done best meeting point brute force approach done --- .../leetcode/arrays/ValidTriangleNumber.java | 84 ++++++++++- .../com/leetcode/math/BestMeetingPoint.java | 141 ++++++++++++++++++ 2 files changed, 218 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/leetcode/math/BestMeetingPoint.java diff --git a/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java b/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java index bab45ded..cdbfb0c5 100644 --- a/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java +++ b/src/main/java/com/leetcode/arrays/ValidTriangleNumber.java @@ -21,27 +21,97 @@ * 2,2,3 *

* Note: - * The length of the given array won't exceed 1000. - * The integers in the given array are in the range of [0, 1000]. + * - The length of the given array won't exceed 1000. + * - The integers in the given array are in the range of [0, 1000]. + * - Triangle Property: Sum of any 2 sides must be greater than the 3rd side. * * @author rampatra * @since 2019-08-07 */ public class ValidTriangleNumber { - public static int triangleNumber(int[] nums) { - int l = 0; - int r = nums.length - 1; + /** + * Time complexity : O(n^2 log n). In worst case, the inner loop will take n log n (binary search applied n times). + * Space complexity : O(log n). Sorting takes O(log n) space. + * Runtime: 13 ms. + * + * @param nums + * @return + */ + public static int triangleNumberUsingBinarySearch(int[] nums) { int noOfTriangles = 0; Arrays.sort(nums); - // todo + for (int i = 0; i < nums.length - 2; i++) { + int k = i + 2; + for (int j = i + 1; j < nums.length - 1; j++) { + k = binarySearch(nums, k, nums.length - 1, nums[i] + nums[j]); + if (k - j - 1 > 0) { + noOfTriangles += k - j - 1; + } + } + } + + return noOfTriangles; + } + + private static int binarySearch(int[] nums, int low, int high, int num) { + while (low <= high) { + int mid = (low + high) / 2; + if (nums[mid] < num) { + low = mid + 1; + } else { + high = mid - 1; + } + } + + return low; + } + + /** + * The concept is simple. For each pair (i,j), find the value of k such that nums[i] + nums[j] > nums[k] (as per + * triangle property). Once we find k then we can form k- j - 1 triangles. + * + * Time Complexity: O(n^2) Loop of k and j will be executed O(n^2) times in total, because, we do + * not reinitialize the value of k for a new value of j chosen(for the same i). Thus, the complexity + * will be O(n^2 + n^2) = O(n^2). + * Space Complexity: O(log n). Sorting takes O(log n) space. + * Runtime: 5 ms. + * + * @param nums + * @return + */ + public static int triangleNumber(int[] nums) { + int noOfTriangles = 0; + Arrays.sort(nums); + + for (int i = 0; i < nums.length - 2; i++) { + int k = i + 2; + for (int j = i + 1; j < nums.length - 1; j++) { + while (k < nums.length && nums[i] + nums[j] > nums[k]) { + k++; + } + if (k - j - 1 > 0) { + noOfTriangles += k - j - 1; + } + } + } return noOfTriangles; } public static void main(String[] args) { + assertEquals(0, triangleNumberUsingBinarySearch(new int[]{})); + assertEquals(0, triangleNumberUsingBinarySearch(new int[]{1})); + assertEquals(3, triangleNumberUsingBinarySearch(new int[]{2, 2, 3, 4})); + assertEquals(0, triangleNumberUsingBinarySearch(new int[]{0, 1, 0, 1})); + assertEquals(7, triangleNumberUsingBinarySearch(new int[]{1, 2, 3, 4, 5, 6})); + + assertEquals(0, triangleNumber(new int[]{})); + assertEquals(0, triangleNumber(new int[]{1})); assertEquals(3, triangleNumber(new int[]{2, 2, 3, 4})); + assertEquals(0, triangleNumber(new int[]{0, 1, 0, 1})); + assertEquals(7, triangleNumber(new int[]{1, 2, 3, 4, 5, 6})); } -} +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/math/BestMeetingPoint.java b/src/main/java/com/leetcode/math/BestMeetingPoint.java new file mode 100644 index 00000000..84d96fe9 --- /dev/null +++ b/src/main/java/com/leetcode/math/BestMeetingPoint.java @@ -0,0 +1,141 @@ +package com.leetcode.math; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/best-meeting-point/ + * Description: + * A group of two or more people wants to meet and minimize the total travel distance. You are given a 2D grid + * of values 0 or 1, where each 1 marks the home of someone in the group. The distance is calculated using + * Manhattan Distance, where distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|. + * + * Example: + * + * Input: + * + * 1 - 0 - 0 - 0 - 1 + * | | | | | + * 0 - 0 - 0 - 0 - 0 + * | | | | | + * 0 - 0 - 1 - 0 - 0 + * + * Output: 6 + * + * Explanation: Given three people living at (0,0), (0,4), and (2,2): + * The point (0,2) is an ideal meeting point, as the total travel distance + * of 2+2+2=6 is minimal. So, return 6. + * + * @author rampatra + * @since 2019-08-07 + */ +public class BestMeetingPoint { + + /** + * Time Complexity: O(k * i * j) + * Space Complexity: O(1) + * where, + * k = no of homes + * i = rows in grid + * j = columns in grid + * + * So, if i = j = k then you can see that it has a O(n^3) time complexity. + * + * @param grid + * @return + */ + public static int minTotalDistanceBrutForce(int[][] grid) { + int minDistance = Integer.MAX_VALUE; + List> homeCoordinates = new ArrayList<>(); + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + if (grid[i][j] == 1) { + homeCoordinates.add(Arrays.asList(i, j)); + } + } + } + + for (int i = 0; i < grid.length; i++) { + for (int j = 0; j < grid[0].length; j++) { + int distance = 0; + for (int k = 0; k < homeCoordinates.size(); k++) { + distance += Math.abs(homeCoordinates.get(k).get(0) - i) + Math.abs(homeCoordinates.get(k).get(1) - j); + } + minDistance = Math.min(minDistance, distance); + } + } + + return minDistance; + } + + public static int minTotalDistance(int[][] grid) { + return -1; // todo + } + + public static void main(String[] args) { + assertEquals(6, minTotalDistanceBrutForce(new int[][]{ + {1,0,0,0,1}, + {0,0,0,0,0}, + {0,0,1,0,0} + })); + + assertEquals(4, minTotalDistanceBrutForce(new int[][]{ + {1,0,0,0,1}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + + assertEquals(1, minTotalDistanceBrutForce(new int[][]{ + {1,1,0,0,0}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + + assertEquals(0, minTotalDistanceBrutForce(new int[][]{ + {1,0,0,0,0}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + + assertEquals(0, minTotalDistanceBrutForce(new int[][]{ + {0,0,0,0,0}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + + assertEquals(6, minTotalDistance(new int[][]{ + {1,0,0,0,1}, + {0,0,0,0,0}, + {0,0,1,0,0} + })); + + assertEquals(4, minTotalDistance(new int[][]{ + {1,0,0,0,1}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + + assertEquals(1, minTotalDistance(new int[][]{ + {1,1,0,0,0}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + + assertEquals(0, minTotalDistance(new int[][]{ + {1,0,0,0,0}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + + assertEquals(0, minTotalDistance(new int[][]{ + {0,0,0,0,0}, + {0,0,0,0,0}, + {0,0,0,0,0} + })); + } +} \ No newline at end of file From a4817fe188f23bb17d90d97dc9571d421da289f4 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 9 Aug 2019 17:13:33 +0100 Subject: [PATCH 37/70] Sparse matrix multiplication done --- .../arrays/SparseMatrixMultiplication.java | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/main/java/com/leetcode/arrays/SparseMatrixMultiplication.java diff --git a/src/main/java/com/leetcode/arrays/SparseMatrixMultiplication.java b/src/main/java/com/leetcode/arrays/SparseMatrixMultiplication.java new file mode 100644 index 00000000..78c884e4 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/SparseMatrixMultiplication.java @@ -0,0 +1,87 @@ +package com.leetcode.arrays; + +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/sparse-matrix-multiplication/ + * Description: + * Given two sparse matrices A and B, return the result of AB. + * + * You may assume that A's column number is equal to B's row number. + * + * Example: + * + * Input: + * + * A = [ + * [ 1, 0, 0], + * [-1, 0, 3] + * ] + * + * B = [ + * [ 7, 0, 0 ], + * [ 0, 0, 0 ], + * [ 0, 0, 1 ] + * ] + * + * Output: + * + * | 1 0 0 | | 7 0 0 | | 7 0 0 | + * AB = | -1 0 3 | x | 0 0 0 | = | -7 0 3 | + * | 0 0 1 | + * + * @author rampatra + * @since 2019-08-09 + */ +public class SparseMatrixMultiplication { + + /** + * Time Complexity: O(Arow * Acol * Bcol) + * Space Complexity: O(Arow * Bcol) + * + * @param A + * @param B + * @return + */ + public static int[][] multiply(int[][] A, int[][] B) { + int[][] AB = new int[A.length][B[0].length]; + + for (int Bcol = 0; Bcol < B[0].length; Bcol++) { + for (int Arow = 0; Arow < A.length; Arow++) { + int sum = 0; + for (int Acol = 0; Acol < A[0].length; Acol++) { + sum += A[Arow][Acol] * B[Acol][Bcol]; + } + AB[Arow][Bcol] = sum; + } + } + + return AB; + } + + public static void main(String[] args) { + assertEquals(Arrays.deepToString(new int[][]{ + {7, 0, 0}, + {-7, 0, 3} + }), Arrays.deepToString(multiply(new int[][]{ + {1, 0, 0}, + {-1, 0, 3} + }, new int[][]{ + {7, 0, 0}, + {0, 0, 0}, + {0, 0, 1} + }))); + + assertEquals(Arrays.deepToString(new int[][]{ + {0} + }), Arrays.deepToString(multiply(new int[][]{ + {0, 1} + }, new int[][]{ + {1}, + {0} + }))); + } +} \ No newline at end of file From 24fe94684aa4b5a9cbf646e7ada6c9d708218802 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 9 Aug 2019 20:48:52 +0100 Subject: [PATCH 38/70] LongestSubstringWithKDistinctCharacters done --- ...ngestSubstringWithKDistinctCharacters.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java diff --git a/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java b/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java new file mode 100644 index 00000000..58863c3d --- /dev/null +++ b/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java @@ -0,0 +1,80 @@ +package com.leetcode.maps.slidingwindow; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/longest-substring-with-at-most-k-distinct-characters/ + * Description: + * Given a string, find the length of the longest substring T that contains at most k distinct characters. + *

+ * Example 1: + * Input: s = "eceba", k = 2 + * Output: 3 + * Explanation: T is "ece" which its length is 3. + *

+ * Example 2: + * Input: s = "aa", k = 1 + * Output: 2 + * Explanation: T is "aa" which its length is 2. + * + * @author rampatra + * @since 2019-08-09 + */ +public class LongestSubstringWithKDistinctCharacters { + + /** + * Time Complexity: O(n) + * Space Complexity: O(k), as we keep at most k characters in the hash table + * + * @param str + * @param k + * @return + */ + public static int lengthOfLongestSubstringKDistinct(String str, int k) { + int length = 0; + Map letterCountInWindow = new HashMap<>(); + + int i = 0; // start of window + int j = i; // end of window + + while (j < str.length()) { + char ch = str.charAt(j); + + letterCountInWindow.putIfAbsent(ch, 0); + letterCountInWindow.put(ch, letterCountInWindow.get(ch) + 1); + + // when number of distinct characters in the window exceeds k: + // - update length + // - remove the first character in the window or reduce its count if the window had more than one of this character + // - lastly, move the window forward + if (letterCountInWindow.keySet().size() > k) { + char firstChar = str.charAt(i); + int firstCharCount = letterCountInWindow.get(firstChar); + if (firstCharCount > 1) { + letterCountInWindow.put(firstChar, firstCharCount - 1); + } else { + letterCountInWindow.remove(firstChar); + } + length = Math.max(length, j - i); + i++; + } + j++; + } + + return length == 0 ? j - i : length; + } + + public static void main(String[] args) { + assertEquals(3, lengthOfLongestSubstringKDistinct("eceba", 2)); + assertEquals(7, lengthOfLongestSubstringKDistinct("eceeeeeba", 2)); + assertEquals(2, lengthOfLongestSubstringKDistinct("abcdef", 2)); + assertEquals(1, lengthOfLongestSubstringKDistinct("a", 1)); + assertEquals(2, lengthOfLongestSubstringKDistinct("aa", 1)); + assertEquals(3, lengthOfLongestSubstringKDistinct("aaa", 1)); + assertEquals(0, lengthOfLongestSubstringKDistinct("aa", 0)); + } +} From 5fd40fc97f4ad1673924c87fe08bc47cd594c528 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Fri, 9 Aug 2019 20:51:20 +0100 Subject: [PATCH 39/70] Minor improvement --- .../slidingwindow/LongestSubstringWithKDistinctCharacters.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java b/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java index 58863c3d..21cfab23 100644 --- a/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java +++ b/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java @@ -44,8 +44,7 @@ public static int lengthOfLongestSubstringKDistinct(String str, int k) { while (j < str.length()) { char ch = str.charAt(j); - letterCountInWindow.putIfAbsent(ch, 0); - letterCountInWindow.put(ch, letterCountInWindow.get(ch) + 1); + letterCountInWindow.put(ch, letterCountInWindow.getOrDefault(ch, 0) + 1); // when number of distinct characters in the window exceeds k: // - update length From 813a3c51feb1933b6a14b7ec301f738568abc4bb Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 11 Aug 2019 08:11:58 +0100 Subject: [PATCH 40/70] Insert Delete GetRandom O(1): done --- .../design/InsertDeleteGetRandom.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/main/java/com/leetcode/design/InsertDeleteGetRandom.java diff --git a/src/main/java/com/leetcode/design/InsertDeleteGetRandom.java b/src/main/java/com/leetcode/design/InsertDeleteGetRandom.java new file mode 100644 index 00000000..a6c2f376 --- /dev/null +++ b/src/main/java/com/leetcode/design/InsertDeleteGetRandom.java @@ -0,0 +1,106 @@ +package com.leetcode.design; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/insert-delete-getrandom-o1/ + * Description: + * 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. + * + * Example: + * + * // Init an empty set. + * RandomizedSet randomSet = new RandomizedSet(); + * + * // Inserts 1 to the set. Returns true as 1 was inserted successfully. + * randomSet.insert(1); + * + * // Returns false as 2 does not exist in the set. + * randomSet.remove(2); + * + * // Inserts 2 to the set, returns true. Set now contains [1,2]. + * randomSet.insert(2); + * + * // getRandom should return either 1 or 2 randomly. + * randomSet.getRandom(); + * + * // Removes 1 from the set, returns true. Set now contains [2]. + * randomSet.remove(1); + * + * // 2 was already in the set, so return false. + * randomSet.insert(2); + * + * // Since 2 is the only number in the set, getRandom always return 2. + * randomSet.getRandom(); + * + * Runtime: 8 ms. + * + * @param s + * @param t + * @return + */ + public static boolean isIsomorphic(String s, String t) { + + Map sToTCharMap = new HashMap<>(); + Map tToSCharMap = new HashMap<>(); + + for (int i = 0; i < s.length(); i++) { + char chFromS = s.charAt(i); + char chFromT = t.charAt(i); + if (sToTCharMap.get(chFromS) == null && tToSCharMap.get(chFromT) == null) { + sToTCharMap.put(chFromS, chFromT); + tToSCharMap.put(chFromT, chFromS); + } + Character mappedChFromSToT = sToTCharMap.get(chFromS); + if (mappedChFromSToT == null || mappedChFromSToT != chFromT) { + return false; + } + } + + return true; + } + + /** + * Time Complexity: + * Space Complexity: + * Runtime: 3 ms. + * + * @param s + * @param t + * @return + */ + public static boolean isIsomorphicWithoutMaps(String s, String t) { + int[] charMap = new int[512]; + for (int i = 0; i < s.length(); i++) { + char chFromS = s.charAt(i); + char chFromT = t.charAt(i); + if (charMap[chFromS] != charMap[chFromT + 256]) { + return false; + } + charMap[chFromS] = charMap[chFromT + 256] = i + 1; + } + + return true; + } + + public static void main(String[] args) { + assertTrue(isIsomorphic("egg", "add")); + assertFalse(isIsomorphic("foo", "bar")); + assertTrue(isIsomorphic("paper", "title")); + assertFalse(isIsomorphic("ab", "aa")); + + assertTrue(isIsomorphicWithoutMaps("egg", "add")); + assertFalse(isIsomorphicWithoutMaps("foo", "bar")); + assertTrue(isIsomorphicWithoutMaps("paper", "title")); + assertFalse(isIsomorphicWithoutMaps("ab", "aa")); + } +} From b449afdc5e42d5e99ac120e6a18940211cb81afb Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 11 Aug 2019 22:27:16 +0100 Subject: [PATCH 42/70] zigzag traversal: done --- .../BinaryTreeZigZagLevelOrderTraversal.java | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 src/main/java/com/leetcode/trees/BinaryTreeZigZagLevelOrderTraversal.java diff --git a/src/main/java/com/leetcode/trees/BinaryTreeZigZagLevelOrderTraversal.java b/src/main/java/com/leetcode/trees/BinaryTreeZigZagLevelOrderTraversal.java new file mode 100644 index 00000000..1a54d952 --- /dev/null +++ b/src/main/java/com/leetcode/trees/BinaryTreeZigZagLevelOrderTraversal.java @@ -0,0 +1,100 @@ +package com.leetcode.trees; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/ + * Description: + * Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to right, then + * right to left for the next level and alternate between). + * + * For example: + * Given binary tree [3,9,20,null,null,15,7], + * 3 + * / \ + * 9 20 + * / \ + * 15 7 + * return its zigzag level order traversal as: + * [ + * [3], + * [20,9], + * [15,7] + * ] + * + * @author rampatra + * @since 2019-08-11 + */ +public class BinaryTreeZigZagLevelOrderTraversal { + + /** + * Time Complexity: + * Space Complexity: + * Runtime: 1 ms. + * + * @param root + * @return + */ + public static List> zigzagLevelOrder(TreeNode root) { + + int levelNo = 0; + LinkedList currLevel = new LinkedList<>(); + List> levelOrderTraversal = new LinkedList<>(); + + if (root == null) { + return levelOrderTraversal; + } + + Queue queue = new LinkedList<>(); + queue.add(root); + queue.add(null); + + while (!queue.isEmpty()) { + + TreeNode treeNode = queue.poll(); + + if (treeNode == null) { + levelOrderTraversal.add(currLevel); + currLevel = new LinkedList<>(); + levelNo++; + + if (queue.size() > 0) { + queue.add(null); + } + } else { + if (levelNo % 2 == 0) { + currLevel.add(treeNode.val); + } else { + currLevel.add(0, treeNode.val); + } + if (treeNode.left != null) queue.add(treeNode.left); + if (treeNode.right != null) queue.add(treeNode.right); + } + } + + return levelOrderTraversal; + } + + public static void main(String[] args) { + /* + Binary Tree + + 1 + / \ + 2 3 + / \ + 4 5 + */ + TreeNode tree = new TreeNode(1); + tree.left = new TreeNode(2); + tree.right = new TreeNode(3); + tree.left.left = new TreeNode(4); + tree.left.right = new TreeNode(5); + + assertEquals("[[1], [3, 2], [4, 5]]", zigzagLevelOrder(tree).toString()); + assertEquals("[]", zigzagLevelOrder(null).toString()); + } +} From 869bc3099f0e51705adec71e345e69cb6452d26f Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 12 Aug 2019 10:44:50 +0100 Subject: [PATCH 43/70] flatten nestlist + minor refactorings: done --- .../recursion/FlattenNestListIterator.java | 69 +++++++++++++++++++ .../com/leetcode/recursion/NestedInteger.java | 46 +++++++++++++ .../NestedListWeightSum.java | 2 +- .../NestedListWeightSumII.java | 38 +--------- 4 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/leetcode/recursion/FlattenNestListIterator.java create mode 100644 src/main/java/com/leetcode/recursion/NestedInteger.java rename src/main/java/com/leetcode/{arrays => recursion}/NestedListWeightSum.java (98%) rename src/main/java/com/leetcode/{arrays => recursion}/NestedListWeightSumII.java (78%) diff --git a/src/main/java/com/leetcode/recursion/FlattenNestListIterator.java b/src/main/java/com/leetcode/recursion/FlattenNestListIterator.java new file mode 100644 index 00000000..b443e954 --- /dev/null +++ b/src/main/java/com/leetcode/recursion/FlattenNestListIterator.java @@ -0,0 +1,69 @@ +package com.leetcode.recursion; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/flatten-nested-list-iterator/ + * Description: + * Given a nested list of integers, implement an iterator to flatten it. + * + * Each element is either an integer, or a list -- whose elements may also be integers or other lists. + * + * Example 1: + * Input: [[1,1],2,[1,1]] + * Output: [1,1,2,1,1] + * Explanation: By calling next repeatedly until hasNext returns false, + * the order of elements returned by next should be: [1,1,2,1,1]. + * + * Example 2: + * Input: [1,[4,[6]]] + * Output: [1,4,6] + * Explanation: By calling next repeatedly until hasNext returns false, + * the order of elements returned by next should be: [1,4,6]. + * + * Runtime: 2 ms. + * + * @author rampatra + * @since 2019-08-12 + */ +public class FlattenNestListIterator implements Iterator { + + private int index; + private List flattenedList; + + public FlattenNestListIterator(List nestedList) { + index = 0; + flattenedList = getFlattenedList(nestedList); + } + + private List getFlattenedList(List nestedList) { + List flattenedList = new ArrayList<>(); + + for (NestedInteger nestedInteger : nestedList) { + if (nestedInteger.isInteger()) { + flattenedList.add(nestedInteger.getInteger()); + } else { + flattenedList.addAll(getFlattenedList(nestedInteger.getList())); + } + } + + return flattenedList; + } + + @Override + public Integer next() { + return flattenedList.get(index++); + } + + @Override + public boolean hasNext() { + return index < flattenedList.size(); + } + + public static void main(String[] args) { + // TODO add some test cases + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/recursion/NestedInteger.java b/src/main/java/com/leetcode/recursion/NestedInteger.java new file mode 100644 index 00000000..1bba817e --- /dev/null +++ b/src/main/java/com/leetcode/recursion/NestedInteger.java @@ -0,0 +1,46 @@ +package com.leetcode.recursion; + +import java.util.ArrayList; +import java.util.List; + +/** + * Class needed for various problems like {@link NestedListWeightSumII}, {@link FlattenNestListIterator}, etc. + * + * @author rampatra + * @since 2019-08-12 + */ +public class NestedInteger { + + private Integer integer; + private List list; + + public NestedInteger() { + this.list = new ArrayList<>(); + } + + public NestedInteger(int integer) { + this.integer = integer; + this.list = new ArrayList<>(); + } + + public boolean isInteger() { + return this.integer != null; + } + + public Integer getInteger() { + return integer; + } + + public void setInteger(Integer integer) { + this.integer = integer; + } + + public List getList() { + return list; + } + + public NestedInteger add(NestedInteger nestedInteger) { + this.list.add(nestedInteger); + return this; + } +} diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSum.java b/src/main/java/com/leetcode/recursion/NestedListWeightSum.java similarity index 98% rename from src/main/java/com/leetcode/arrays/NestedListWeightSum.java rename to src/main/java/com/leetcode/recursion/NestedListWeightSum.java index 4886c445..1079b29f 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSum.java +++ b/src/main/java/com/leetcode/recursion/NestedListWeightSum.java @@ -1,4 +1,4 @@ -package com.leetcode.arrays; +package com.leetcode.recursion; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java b/src/main/java/com/leetcode/recursion/NestedListWeightSumII.java similarity index 78% rename from src/main/java/com/leetcode/arrays/NestedListWeightSumII.java rename to src/main/java/com/leetcode/recursion/NestedListWeightSumII.java index 379c8f5e..eadd121b 100644 --- a/src/main/java/com/leetcode/arrays/NestedListWeightSumII.java +++ b/src/main/java/com/leetcode/recursion/NestedListWeightSumII.java @@ -1,4 +1,4 @@ -package com.leetcode.arrays; +package com.leetcode.recursion; import java.util.*; @@ -77,40 +77,4 @@ public static void main(String[] args) { assertEquals(17, nestedSum(Collections.singletonList(ni))); } -} - -class NestedInteger { - - private Integer integer; - private List list; - - public NestedInteger() { - this.list = new ArrayList<>(); - } - - public NestedInteger(int integer) { - this.integer = integer; - this.list = new ArrayList<>(); - } - - public boolean isInteger() { - return this.integer != null; - } - - public Integer getInteger() { - return integer; - } - - public void setInteger(Integer integer) { - this.integer = integer; - } - - public List getList() { - return list; - } - - public NestedInteger add(NestedInteger nestedInteger) { - this.list.add(nestedInteger); - return this; - } } \ No newline at end of file From 1eafcd907aeb420010ba5aea26105a319081e4ca Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 12 Aug 2019 21:45:52 +0100 Subject: [PATCH 44/70] ClosestBinarySearchTreeValue II: done --- .../trees/ClosestBinarySearchTreeValueII.java | 120 +++++++++++++++--- 1 file changed, 105 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java index 4f5cbe71..e583723a 100644 --- a/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java +++ b/src/main/java/com/leetcode/trees/ClosestBinarySearchTreeValueII.java @@ -1,27 +1,121 @@ package com.leetcode.trees; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; +import java.util.Stack; + import static org.junit.jupiter.api.Assertions.assertEquals; /** * Level: Hard * Problem Link: https://leetcode.com/problems/closest-binary-search-tree-value-ii/ * Problem Description: + * Given a non-empty binary search tree and a target value, find k values in the BST that are closest to the target. + * + * Note: + * - Given target value is a floating point. + * - You may assume k is always valid, that is: k ≤ total nodes. + * - You are guaranteed to have only one unique set of k values in the BST that are closest to the target. + * + * Example: + * Input: root = [4,2,5,1,3], target = 3.714286, and k = 2 * + * 4 + * / \ + * 2 5 + * / \ + * 1 3 + * + * Output: [4,3] + * + * Follow up: + * Assume that the BST is balanced, could you solve it in less than O(n) runtime (where n = total nodes)? * * @author rampatra * @since 2019-07-31 */ public class ClosestBinarySearchTreeValueII { + + /** + * The idea is simple. We do the inorder traversal and keep the values less than or equal to target in a stack and + * the values greater than target in a queue. And finally, we compare values from both stack and queue and take + * whichever is the closest to target value each time. + * + * Note: We can optimize it even further in terms of space. We can get rid of the stack and queue and just fill up + * the result list in the recursive inOrder call. Once the result list is of size k, we can compare and remove the + * farthest value and insert the closer value. See {@link ClosestBinarySearchTreeValueII#closestKValuesOptimized(TreeNode, double, int)}. + * + * @param root + * @param target + * @param k + * @return + */ + public static List closestKValues(TreeNode root, double target, int k) { + int count = 0; + List closestKValues = new LinkedList<>(); + + Stack predecessors = new Stack<>(); + Queue successors = new LinkedList<>(); + inOrder(root, predecessors, successors, target, k); + + while (count < k) { + if (predecessors.empty()) { + closestKValues.add(successors.poll()); + } else if (successors.isEmpty()) { + closestKValues.add(predecessors.pop()); + } else if (Math.abs(target - predecessors.peek()) < Math.abs(target - successors.peek())) { + closestKValues.add(predecessors.pop()); + } else { + closestKValues.add(successors.poll()); + } + count++; + } + + return closestKValues; + } + + private static void inOrder(TreeNode root, Stack predecessors, Queue successors, double target, int k) { + if (root == null || successors.size() == k) return; + inOrder(root.left, predecessors, successors, target, k); + if (root.val <= target) { + predecessors.add(root.val); + } else { + successors.add(root.val); + } + inOrder(root.right, predecessors, successors, target, k); + } + + /** - * @param node - * @param parentNode - * @param val - * @param diff + * This approach is similar to the above one but it doesn't use stack or queue. + * + * @param root + * @param target + * @param k * @return */ - public static TreeNode findNodeWithClosestValue(TreeNode node, TreeNode parentNode, int val, int diff) { - return null; + public static List closestKValuesOptimized(TreeNode root, double target, int k) { + LinkedList closestKValues = new LinkedList<>(); + inOrder(root, target, k, closestKValues); + return closestKValues; + } + + private static void inOrder(TreeNode root, double target, int k, LinkedList closestKValues) { + if (root == null) return; + + inOrder(root.left, target, k, closestKValues); + if (closestKValues.size() == k) { + //if size k, add current and remove head if it's closer to target, otherwise return + if (Math.abs(target - root.val) < Math.abs(target - closestKValues.peekFirst())) + closestKValues.removeFirst(); + else { + return; + } + } + closestKValues.add(root.val); + inOrder(root.right, target, k, closestKValues); } public static void main(String[] args) { @@ -46,13 +140,8 @@ public static void main(String[] args) { root.left.left.right = new TreeNode(6); root.right.right = new TreeNode(20); - assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); - assertEquals(13, findNodeWithClosestValue(root, root, 13, Integer.MAX_VALUE).val); - assertEquals(9, findNodeWithClosestValue(root, root, 9, Integer.MAX_VALUE).val); - assertEquals(2, findNodeWithClosestValue(root, root, 2, Integer.MAX_VALUE).val); - assertEquals(2, findNodeWithClosestValue(root, root, 1, Integer.MAX_VALUE).val); - assertEquals(6, findNodeWithClosestValue(root, root, 6, Integer.MAX_VALUE).val); - assertEquals(13, findNodeWithClosestValue(root, root, 11, Integer.MAX_VALUE).val); // tie b/w 9 and 13 + assertEquals("[9, 8, 7, 6, 5]", closestKValues(root, 8.5, 5).toString()); + assertEquals("[5, 6, 7, 8, 9]", closestKValuesOptimized(root, 8.5, 5).toString()); /* BST looks like: @@ -67,10 +156,11 @@ public static void main(String[] args) { root.left = new TreeNode(7); root.right = new TreeNode(13); root.left.left = new TreeNode(5); - root.left.right = new TreeNode(8); root.right.left = new TreeNode(13); + root.left.right = new TreeNode(8); root.right.right = new TreeNode(20); - assertEquals(13, findNodeWithClosestValue(root, root, 15, Integer.MAX_VALUE).val); + assertEquals("[13, 13, 9, 20, 8]", closestKValues(root, 14, 5).toString()); + assertEquals("[8, 9, 13, 13, 20]", closestKValuesOptimized(root, 14, 5).toString()); } } From 062d4fc8507839d1b98e34c64160e685f68bc8ee Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 15 Aug 2019 13:17:19 +0100 Subject: [PATCH 45/70] Sliding Window Problems: done --- .../leetcode/arrays/ShortestWordDistance.java | 4 +- .../IsomorphicStrings.java | 2 +- .../RepeatedDnaSequence.java | 2 +- .../ShortestWordDistanceII.java | 2 +- .../{maps => hashtables}/TwoSumIII.java | 2 +- ...ngestSubstringWithKDistinctCharacters.java | 23 ++-- ...stSubstringWithoutRepeatingCharacters.java | 128 ++++++++++++++++++ .../slidingwindow/MinimumWindowSubstring.java | 104 ++++++++++++++ 8 files changed, 252 insertions(+), 15 deletions(-) rename src/main/java/com/leetcode/{maps => hashtables}/IsomorphicStrings.java (98%) rename src/main/java/com/leetcode/{maps => hashtables}/RepeatedDnaSequence.java (98%) rename src/main/java/com/leetcode/{maps => hashtables}/ShortestWordDistanceII.java (99%) rename src/main/java/com/leetcode/{maps => hashtables}/TwoSumIII.java (98%) rename src/main/java/com/leetcode/{maps => hashtables}/slidingwindow/LongestSubstringWithKDistinctCharacters.java (78%) create mode 100644 src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java create mode 100644 src/main/java/com/leetcode/hashtables/slidingwindow/MinimumWindowSubstring.java diff --git a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java index 50b198cd..5cd0c821 100644 --- a/src/main/java/com/leetcode/arrays/ShortestWordDistance.java +++ b/src/main/java/com/leetcode/arrays/ShortestWordDistance.java @@ -1,5 +1,7 @@ package com.leetcode.arrays; +import com.leetcode.hashtables.ShortestWordDistanceII; + import static org.junit.jupiter.api.Assertions.assertEquals; /** @@ -16,7 +18,7 @@ * * Note: You may assume that word1 does not equal to word2, and word1 and word2 are both in the list. * - * Lastly, for a more complex variant, see {@link com.leetcode.maps.ShortestWordDistanceII}. + * Lastly, for a more complex variant, see {@link ShortestWordDistanceII}. * * @author rampatra * @since 2019-07-31 diff --git a/src/main/java/com/leetcode/maps/IsomorphicStrings.java b/src/main/java/com/leetcode/hashtables/IsomorphicStrings.java similarity index 98% rename from src/main/java/com/leetcode/maps/IsomorphicStrings.java rename to src/main/java/com/leetcode/hashtables/IsomorphicStrings.java index 78bc02bd..f9a7f4eb 100644 --- a/src/main/java/com/leetcode/maps/IsomorphicStrings.java +++ b/src/main/java/com/leetcode/hashtables/IsomorphicStrings.java @@ -1,4 +1,4 @@ -package com.leetcode.maps; +package com.leetcode.hashtables; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java b/src/main/java/com/leetcode/hashtables/RepeatedDnaSequence.java similarity index 98% rename from src/main/java/com/leetcode/maps/RepeatedDnaSequence.java rename to src/main/java/com/leetcode/hashtables/RepeatedDnaSequence.java index a4eddb4a..7674273d 100644 --- a/src/main/java/com/leetcode/maps/RepeatedDnaSequence.java +++ b/src/main/java/com/leetcode/hashtables/RepeatedDnaSequence.java @@ -1,4 +1,4 @@ -package com.leetcode.maps; +package com.leetcode.hashtables; import java.util.*; diff --git a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java b/src/main/java/com/leetcode/hashtables/ShortestWordDistanceII.java similarity index 99% rename from src/main/java/com/leetcode/maps/ShortestWordDistanceII.java rename to src/main/java/com/leetcode/hashtables/ShortestWordDistanceII.java index ecb6c9b9..3932cebf 100644 --- a/src/main/java/com/leetcode/maps/ShortestWordDistanceII.java +++ b/src/main/java/com/leetcode/hashtables/ShortestWordDistanceII.java @@ -1,4 +1,4 @@ -package com.leetcode.maps; +package com.leetcode.hashtables; import java.util.ArrayList; import java.util.HashMap; diff --git a/src/main/java/com/leetcode/maps/TwoSumIII.java b/src/main/java/com/leetcode/hashtables/TwoSumIII.java similarity index 98% rename from src/main/java/com/leetcode/maps/TwoSumIII.java rename to src/main/java/com/leetcode/hashtables/TwoSumIII.java index 22f0748f..88916db0 100644 --- a/src/main/java/com/leetcode/maps/TwoSumIII.java +++ b/src/main/java/com/leetcode/hashtables/TwoSumIII.java @@ -1,4 +1,4 @@ -package com.leetcode.maps; +package com.leetcode.hashtables; import java.util.HashMap; import java.util.Map; diff --git a/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java b/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithKDistinctCharacters.java similarity index 78% rename from src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java rename to src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithKDistinctCharacters.java index 21cfab23..84a0773c 100644 --- a/src/main/java/com/leetcode/maps/slidingwindow/LongestSubstringWithKDistinctCharacters.java +++ b/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithKDistinctCharacters.java @@ -1,4 +1,4 @@ -package com.leetcode.maps.slidingwindow; +package com.leetcode.hashtables.slidingwindow; import java.util.HashMap; import java.util.Map; @@ -38,11 +38,11 @@ public static int lengthOfLongestSubstringKDistinct(String str, int k) { int length = 0; Map letterCountInWindow = new HashMap<>(); - int i = 0; // start of window - int j = i; // end of window + int left = 0; // start of window + int right = 0; // end of window - while (j < str.length()) { - char ch = str.charAt(j); + while (right < str.length()) { + char ch = str.charAt(right); letterCountInWindow.put(ch, letterCountInWindow.getOrDefault(ch, 0) + 1); @@ -51,20 +51,20 @@ public static int lengthOfLongestSubstringKDistinct(String str, int k) { // - remove the first character in the window or reduce its count if the window had more than one of this character // - lastly, move the window forward if (letterCountInWindow.keySet().size() > k) { - char firstChar = str.charAt(i); + char firstChar = str.charAt(left); int firstCharCount = letterCountInWindow.get(firstChar); if (firstCharCount > 1) { letterCountInWindow.put(firstChar, firstCharCount - 1); } else { letterCountInWindow.remove(firstChar); } - length = Math.max(length, j - i); - i++; + length = Math.max(length, right - left); + left++; } - j++; + right++; } - return length == 0 ? j - i : length; + return length == 0 ? right - left : length; } public static void main(String[] args) { @@ -75,5 +75,8 @@ public static void main(String[] args) { assertEquals(2, lengthOfLongestSubstringKDistinct("aa", 1)); assertEquals(3, lengthOfLongestSubstringKDistinct("aaa", 1)); assertEquals(0, lengthOfLongestSubstringKDistinct("aa", 0)); + assertEquals(3, lengthOfLongestSubstringKDistinct("aab", 2)); + assertEquals(8, lengthOfLongestSubstringKDistinct("abcabcbb", 3)); + assertEquals(5, lengthOfLongestSubstringKDistinct("pwwkew", 3)); } } diff --git a/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java b/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java new file mode 100644 index 00000000..93a940e4 --- /dev/null +++ b/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithoutRepeatingCharacters.java @@ -0,0 +1,128 @@ +package com.leetcode.hashtables.slidingwindow; + +import java.util.HashSet; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/longest-substring-without-repeating-characters/ + * Description: + * Given a string, find the length of the longest substring without repeating characters. + *

+ * Example 1: + * Input: "abcabcbb" + * Output: 3 + * Explanation: The answer is "abc", with the length of 3. + *

+ * Example 2: + * Input: "bbbbb" + * Output: 1 + * Explanation: The answer is "b", with the length of 1. + *

+ * Example 3: + * Input: "pwwkew" + * Output: 3 + * Explanation: The answer is "wke", with the length of 3. + * Note that the answer must be a substring, "pwke" is a subsequence and not a substring. + * + * @author rampatra + * @since 2019-08-15 + */ +public class LongestSubstringWithoutRepeatingCharacters { + + /** + * Sliding Window Approach (using map). + *

+ * Note: + * If we know that the charset is rather small, we can replace the Map with an integer array as direct access table. + *

+ * Commonly used tables are: + *

+ * int[26] for Letters 'a' - 'z' or 'A' - 'Z' + * int[128] for ASCII + * int[256] for Extended ASCII + *

+ * Runtime: 8 ms. + * + * @param s + * @return + */ + public static int lengthOfLongestSubstring(String s) { + int left = 0; + int right = 0; + int longestSubstringLen = 0; + Set charsInWindow = new HashSet<>(); + + + while (right < s.length()) { + + if (charsInWindow.contains(s.charAt(right))) { + while (s.charAt(left) != s.charAt(right)) { + longestSubstringLen = Math.max(longestSubstringLen, right - left); + charsInWindow.remove(s.charAt(left)); + left++; + } + left++; + } + + charsInWindow.add(s.charAt(right)); + right++; + } + + return Math.max(longestSubstringLen, right - left); + } + + /** + * Sliding Window Approach using int array. + * + * Runtime: 2 ms. + * + * @param s + * @return + */ + public static int lengthOfLongestSubstringNoMap(String s) { + int left = 0; + int right = 0; + int longestSubstringLen = 0; + int[] charsInWindow = new int[128]; + + // keep moving forward the right pointer and adding characters to the window + while (right < s.length()) { + + // once we encounter repeated characters, move the left pointer until the repeated character is removed + if (charsInWindow[s.charAt(right)] == 1) { + while (s.charAt(left) != s.charAt(right)) { + longestSubstringLen = Math.max(longestSubstringLen, right - left); + charsInWindow[s.charAt(left)] = 0; + left++; + } + left++; + } + + charsInWindow[s.charAt(right)] = 1; + right++; + } + + return Math.max(longestSubstringLen, right - left); + } + + public static void main(String[] args) { + assertEquals(0, lengthOfLongestSubstring("")); + assertEquals(1, lengthOfLongestSubstring(" ")); + assertEquals(1, lengthOfLongestSubstring("a")); + assertEquals(2, lengthOfLongestSubstring("aab")); + assertEquals(3, lengthOfLongestSubstring("abcabcbb")); + assertEquals(1, lengthOfLongestSubstring("bbbbb")); + assertEquals(3, lengthOfLongestSubstring("pwwkew")); + + assertEquals(0, lengthOfLongestSubstringNoMap("")); + assertEquals(1, lengthOfLongestSubstringNoMap(" ")); + assertEquals(1, lengthOfLongestSubstringNoMap("a")); + assertEquals(2, lengthOfLongestSubstringNoMap("aab")); + assertEquals(3, lengthOfLongestSubstringNoMap("abcabcbb")); + assertEquals(1, lengthOfLongestSubstringNoMap("bbbbb")); + assertEquals(3, lengthOfLongestSubstringNoMap("pwwkew")); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/hashtables/slidingwindow/MinimumWindowSubstring.java b/src/main/java/com/leetcode/hashtables/slidingwindow/MinimumWindowSubstring.java new file mode 100644 index 00000000..5414cdc1 --- /dev/null +++ b/src/main/java/com/leetcode/hashtables/slidingwindow/MinimumWindowSubstring.java @@ -0,0 +1,104 @@ +package com.leetcode.hashtables.slidingwindow; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/minimum-window-substring/ + * Description: + * Given a string S and a string T, find the minimum window in S which will contain all the characters in T in + * complexity O(n). + *

+ * Example: + *

+ * Input: S = "ADOBECODEBANC", T = "ABC" + * Output: "BANC" + *

+ * Note: + * - If there is no such window in S that covers all characters in T, return the empty string "". + * - If there is such window, you are guaranteed that there will always be only one unique minimum window in S. + * + * @author rampatra + * @since 2019-08-13 + */ +public class MinimumWindowSubstring { + + /** + * Sliding Window Approach (using map). + * + * Note: + * If we know that the charset is rather small, we can replace the Map with an integer array as direct access table. + * + * Commonly used tables are: + * + * int[26] for Letters 'a' - 'z' or 'A' - 'Z' + * int[128] for ASCII + * int[256] for Extended ASCII + * + * Runtime: 22 ms. + * + * @param s + * @param t + * @return + */ + public static String minWindow(String s, String t) { + + int left = 0; // start of window + int right = 0; // end of window + int begin = 0; + int windowSize = Integer.MAX_VALUE; + int charsInWindow = 0; // to check whether the window has all the characters in t with the required frequency + + // characters and their counts in t + Map dictT = new HashMap<>(); + for (int i = 0; i < t.length(); i++) { + char ch = t.charAt(i); + dictT.put(ch, dictT.getOrDefault(ch, 0) + 1); + } + + // characters and their counts in the window + Map dictWindow = new HashMap<>(); + + while (right < s.length()) { + char rightChar = s.charAt(right); + int rightCharCount; + dictWindow.put(rightChar, (rightCharCount = dictWindow.getOrDefault(rightChar, 0) + 1)); + + // once the window has a character in t with the required frequency, increment charsInWindow + if (dictT.get(rightChar) != null && dictT.get(rightChar).equals(rightCharCount)) { + charsInWindow++; + } + + // once the window has all characters in t with required frequency then shorten the window by moving the + // left window forward until the window no longer has all characters of t + while (left <= right && charsInWindow == dictT.size()) { + if (right - left < windowSize) { + windowSize = right - left + 1; + begin = left; + } + + char leftChar = s.charAt(left); + Integer leftCharCount = dictWindow.get(leftChar); + dictWindow.put(leftChar, leftCharCount - 1); + + if (dictT.get(leftChar) != null && leftCharCount - 1 < dictT.get(leftChar)) { + charsInWindow--; + } + left++; + } + right++; + } + + return windowSize == Integer.MAX_VALUE ? "" : s.substring(begin, begin + windowSize); + } + + public static void main(String[] args) { + assertEquals("BANC", minWindow("ADOBECODEBANC", "ABC")); + assertEquals("BAC", minWindow("ADOBECODEBAC", "ABC")); + assertEquals("ba", minWindow("bba", "ab")); + assertEquals("baca", minWindow("acbbaca", "aba")); + } +} \ No newline at end of file From 91d26d43c27f4cce4997282be650c0b697d6022a Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 15 Aug 2019 13:58:00 +0100 Subject: [PATCH 46/70] Minor fix --- .../LongestSubstringWithKDistinctCharacters.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithKDistinctCharacters.java b/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithKDistinctCharacters.java index 84a0773c..4b209b6e 100644 --- a/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithKDistinctCharacters.java +++ b/src/main/java/com/leetcode/hashtables/slidingwindow/LongestSubstringWithKDistinctCharacters.java @@ -48,7 +48,7 @@ public static int lengthOfLongestSubstringKDistinct(String str, int k) { // when number of distinct characters in the window exceeds k: // - update length - // - remove the first character in the window or reduce its count if the window had more than one of this character + // - remove the first character in the window or reduce its count if the window has more than one of this character // - lastly, move the window forward if (letterCountInWindow.keySet().size() > k) { char firstChar = str.charAt(left); @@ -64,17 +64,18 @@ public static int lengthOfLongestSubstringKDistinct(String str, int k) { right++; } - return length == 0 ? right - left : length; + return Math.max(length, right - left); } public static void main(String[] args) { assertEquals(3, lengthOfLongestSubstringKDistinct("eceba", 2)); assertEquals(7, lengthOfLongestSubstringKDistinct("eceeeeeba", 2)); + assertEquals(12, lengthOfLongestSubstringKDistinct("bbbeeeeebaaaaaaaaaaa", 2)); assertEquals(2, lengthOfLongestSubstringKDistinct("abcdef", 2)); assertEquals(1, lengthOfLongestSubstringKDistinct("a", 1)); + assertEquals(0, lengthOfLongestSubstringKDistinct("aa", 0)); assertEquals(2, lengthOfLongestSubstringKDistinct("aa", 1)); assertEquals(3, lengthOfLongestSubstringKDistinct("aaa", 1)); - assertEquals(0, lengthOfLongestSubstringKDistinct("aa", 0)); assertEquals(3, lengthOfLongestSubstringKDistinct("aab", 2)); assertEquals(8, lengthOfLongestSubstringKDistinct("abcabcbb", 3)); assertEquals(5, lengthOfLongestSubstringKDistinct("pwwkew", 3)); From 178347086db6101316231e454367a82366c8a214 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Thu, 15 Aug 2019 20:59:02 +0100 Subject: [PATCH 47/70] Word Ladder I: Done --- .../java/com/leetcode/graphs/WordLadder.java | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 src/main/java/com/leetcode/graphs/WordLadder.java diff --git a/src/main/java/com/leetcode/graphs/WordLadder.java b/src/main/java/com/leetcode/graphs/WordLadder.java new file mode 100644 index 00000000..78a76920 --- /dev/null +++ b/src/main/java/com/leetcode/graphs/WordLadder.java @@ -0,0 +1,109 @@ +package com.leetcode.graphs; + + +import javafx.util.Pair; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/word-ladder/ + * Description: + * Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest transformation + * sequence from beginWord to endWord, such that: + *

+ * Only one letter can be changed at a time. Each transformed word must exist in the word list. Note that beginWord + * is not a transformed word. + *

+ * Note: + * - Return 0 if there is no such transformation sequence. + * - All words have the same length. + * - All words contain only lowercase alphabetic characters. + * - You may assume no duplicates in the word list. + * - You may assume beginWord and endWord are non-empty and are not the same. + *

+ * Example 1: + * Input: + * beginWord = "hit", + * endWord = "cog", + * wordList = ["hot","dot","dog","lot","log","cog"] + *

+ * Output: 5 + *

+ * Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog", + * return its length 5. + *

+ * Example 2: + * Input: + * beginWord = "hit" + * endWord = "cog" + * wordList = ["hot","dot","dog","lot","log"] + *

+ * Output: 0 + *

+ * Explanation: The endWord "cog" is not in wordList, therefore no possible transformation. + * + * @author rampatra + * @since 2019-08-15 + */ +public class WordLadder { + + /** + * Runtime: 78 ms. + * + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public static int ladderLength(String beginWord, String endWord, List wordList) { + int L = beginWord.length(); + Map> originalToTransformedWordMap = new HashMap<>(); + Queue> queue = new LinkedList<>(); + + wordList.forEach(word -> { + String transformedWord; + for (int i = 0; i < L; i++) { + transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L); + originalToTransformedWordMap.putIfAbsent(transformedWord, new HashSet<>()); + originalToTransformedWordMap.get(transformedWord).add(word); + } + } + ); + + Set visited = new HashSet<>(); + queue.add(new Pair<>(beginWord, 1)); + visited.add(beginWord); + + while (!queue.isEmpty()) { + Pair currPair = queue.poll(); + String word = currPair.getKey(); + Integer level = currPair.getValue(); + + if (word.equals(endWord)) { + return level; + } + + String transformedWord; + for (int i = 0; i < L; i++) { + transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L); + + for (String originalWord : originalToTransformedWordMap.getOrDefault(transformedWord, Collections.emptySet())) { + if (!visited.contains(originalWord)) { + queue.add(new Pair<>(originalWord, level + 1)); + visited.add(originalWord); + } + } + } + } + + return 0; + } + + public static void main(String[] args) { + assertEquals(5, ladderLength("hit", "cog", Arrays.asList("hot", "dot", "dog", "lot", "log", "cog"))); + assertEquals(0, ladderLength("hit", "cog", Arrays.asList("hot", "dot", "dog", "lot", "log"))); + } +} From d52dbe74aa77f76f1d3c1a29184293a9eeddaa38 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sat, 17 Aug 2019 13:06:15 +0100 Subject: [PATCH 48/70] word ladder done --- src/main/java/com/leetcode/design/AllOne.java | 125 ++++++++++++++ .../java/com/leetcode/graphs/WordLadder.java | 10 +- .../com/leetcode/graphs/WordLadderII.java | 152 ++++++++++++++++++ 3 files changed, 282 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/leetcode/design/AllOne.java create mode 100644 src/main/java/com/leetcode/graphs/WordLadderII.java diff --git a/src/main/java/com/leetcode/design/AllOne.java b/src/main/java/com/leetcode/design/AllOne.java new file mode 100644 index 00000000..51f771d7 --- /dev/null +++ b/src/main/java/com/leetcode/design/AllOne.java @@ -0,0 +1,125 @@ +package com.leetcode.design; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/all-oone-data-structure/ + * Description: + * Implement a data structure supporting the following operations: + * Inc(Key) - Inserts a new key with value 1. Or increments an existing key by 1. Key is guaranteed to be a non-empty + * string. + * Dec(Key) - If Key's value is 1, remove it from the data structure. Otherwise decrements an existing key by 1. If + * the key does not exist, this function does nothing. Key is guaranteed to be a non-empty string. + * GetMaxKey() - Returns one of the keys with maximal value. If no element exists, return an empty string "". + * GetMinKey() - Returns one of the keys with minimal value. If no element exists, return an empty string "". + *

+ * Challenge: Perform all these in O(1) time complexity. + * + * @author rampatra + * @since 2019-08-11 + */ +public class AllOne { + + + + Map keyToValMap; + Map> valToKeyMap; + + /** + * Initialize your data structure here. + */ + public AllOne() { + keyToValMap = new HashMap<>(); + valToKeyMap = new HashMap<>(); + } + + /** + * Inserts a new key with value 1. Or increments an existing key by 1. + */ + public void inc(String key) { + + } + + /** + * Decrements an existing key by 1. If Key's value is 1, remove it from the data structure. + */ + public void dec(String key) { + + } + + /** + * Returns one of the keys with maximal value. + */ + public String getMaxKey() { + return null; + } + + /** + * Returns one of the keys with Minimal value. + */ + public String getMinKey() { + return null; + } + + public static void main(String[] args) { + AllOne allOne = new AllOne(); + allOne.inc("r"); + allOne.inc("r"); + allOne.dec("r"); + allOne.inc("a"); + allOne.inc("b"); + allOne.inc("b"); + assertEquals("b", allOne.getMaxKey()); + assertEquals("a", allOne.getMinKey()); + + allOne = new AllOne(); + allOne.dec("hello"); + assertEquals("", allOne.getMaxKey()); + + allOne = new AllOne(); + allOne.inc("a"); + allOne.inc("b"); + allOne.inc("b"); + allOne.inc("b"); + allOne.inc("b"); + allOne.dec("b"); + allOne.dec("b"); + assertEquals("b", allOne.getMaxKey()); + assertEquals("a", allOne.getMinKey()); + + allOne = new AllOne(); + allOne.inc("hello"); + allOne.inc("hello"); + assertEquals("hello", allOne.getMaxKey()); + assertEquals("hello", allOne.getMinKey()); + allOne.inc("leet"); + assertEquals("hello", allOne.getMaxKey()); + assertEquals("leet", allOne.getMinKey()); + + allOne = new AllOne(); + allOne.inc("a"); + allOne.inc("b"); + allOne.inc("b"); + allOne.inc("c"); + allOne.inc("c"); + allOne.inc("c"); + allOne.dec("b"); + allOne.dec("b"); + assertEquals("a", allOne.getMinKey()); + allOne.dec("a"); + assertEquals("c", allOne.getMaxKey()); + //assertEquals("c", allOne.getMinKey()); + + allOne = new AllOne(); + allOne.inc("hello"); + allOne.dec("hello"); + assertEquals("", allOne.getMaxKey()); + assertEquals("", allOne.getMinKey()); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/graphs/WordLadder.java b/src/main/java/com/leetcode/graphs/WordLadder.java index 78a76920..979fb12e 100644 --- a/src/main/java/com/leetcode/graphs/WordLadder.java +++ b/src/main/java/com/leetcode/graphs/WordLadder.java @@ -51,7 +51,7 @@ public class WordLadder { /** - * Runtime: 78 ms. + * Runtime: 79 ms. * * @param beginWord * @param endWord @@ -60,15 +60,15 @@ public class WordLadder { */ public static int ladderLength(String beginWord, String endWord, List wordList) { int L = beginWord.length(); - Map> originalToTransformedWordMap = new HashMap<>(); + Map> transformedToOriginalWordMap = new HashMap<>(); Queue> queue = new LinkedList<>(); wordList.forEach(word -> { String transformedWord; for (int i = 0; i < L; i++) { transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L); - originalToTransformedWordMap.putIfAbsent(transformedWord, new HashSet<>()); - originalToTransformedWordMap.get(transformedWord).add(word); + transformedToOriginalWordMap.putIfAbsent(transformedWord, new HashSet<>()); + transformedToOriginalWordMap.get(transformedWord).add(word); } } ); @@ -90,7 +90,7 @@ public static int ladderLength(String beginWord, String endWord, List wo for (int i = 0; i < L; i++) { transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L); - for (String originalWord : originalToTransformedWordMap.getOrDefault(transformedWord, Collections.emptySet())) { + for (String originalWord : transformedToOriginalWordMap.getOrDefault(transformedWord, Collections.emptySet())) { if (!visited.contains(originalWord)) { queue.add(new Pair<>(originalWord, level + 1)); visited.add(originalWord); diff --git a/src/main/java/com/leetcode/graphs/WordLadderII.java b/src/main/java/com/leetcode/graphs/WordLadderII.java new file mode 100644 index 00000000..8265c259 --- /dev/null +++ b/src/main/java/com/leetcode/graphs/WordLadderII.java @@ -0,0 +1,152 @@ +package com.leetcode.graphs; + +import javafx.util.Pair; + +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/word-ladder-ii/ + * Description: + * Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformation sequence(s) + * from beginWord to endWord, such that: + *

+ * Only one letter can be changed at a time + * Each transformed word must exist in the word list. Note that beginWord is not a transformed word. + *

+ * Note: + * - Return an empty list if there is no such transformation sequence. + * - All words have the same length. + * - All words contain only lowercase alphabetic characters. + * - You may assume no duplicates in the word list. + * - You may assume beginWord and endWord are non-empty and are not the same. + *

+ * Example 1: + * Input: + * beginWord = "hit", + * endWord = "cog", + * wordList = ["hot","dot","dog","lot","log","cog"] + *

+ * Output: + * [ + * ["hit","hot","dot","dog","cog"], + * ["hit","hot","lot","log","cog"] + * ] + *

+ *

+ * Example 2: + * Input: + * beginWord = "hit" + * endWord = "cog" + * wordList = ["hot","dot","dog","lot","log"] + *

+ * Output: [] + * Explanation: The endWord "cog" is not in wordList, therefore no possible transformation. + * + * @author rampatra + * @since 2019-08-15 + */ +public class WordLadderII { + + /** + * The approach is same as {@link WordLadder}. We calculate the {@code minDistance} from start to end word and also + * keep a map of words and its adjacent words (i.e, with only character difference). After we are done calculating + * the {@code mindistance}, we perform a dfs on the map upto depth {@code minDistance} and if the last word at this + * depth is equal to the end word then we add all words to the result. + * + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public static List> findLadders(String beginWord, String endWord, List wordList) { + int L = beginWord.length(); + List> ladders = new LinkedList<>(); + Map> transformedToOriginalWordMap = new HashMap<>(); + Queue> queue = new LinkedList<>(); + + wordList.forEach(word -> { + String transformedWord; + for (int i = 0; i < L; i++) { + transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L); + transformedToOriginalWordMap.putIfAbsent(transformedWord, new HashSet<>()); + transformedToOriginalWordMap.get(transformedWord).add(word); + } + } + ); + + int minDistance = -1; + Set visited = new HashSet<>(); + queue.add(new Pair<>(beginWord, 1)); + visited.add(beginWord); + + HashMap> connectedNodes = new HashMap<>(); + + while (!queue.isEmpty()) { + Pair currPair = queue.poll(); + String word = currPair.getKey(); + Integer level = currPair.getValue(); + + if (word.equals(endWord) && minDistance == -1) { + minDistance = level - 1; + } + + String transformedWord; + for (int i = 0; i < L; i++) { + transformedWord = word.substring(0, i) + "*" + word.substring(i + 1, L); + + for (String originalWord : transformedToOriginalWordMap.getOrDefault(transformedWord, Collections.emptySet())) { + if (!visited.contains(originalWord)) { + queue.add(new Pair<>(originalWord, level + 1)); + visited.add(originalWord); + } + + if (!word.equals(originalWord)) { + connectedNodes.putIfAbsent(word, new HashSet<>()); + connectedNodes.get(word).add(originalWord); + } + } + } + } + + dfs(ladders, new LinkedHashSet<>(), connectedNodes, beginWord, endWord, 0, minDistance); + + return ladders; + } + + /** + * Perform dfs on the map which contains words and its adjacent words. + * + * @param ladders + * @param ladder + * @param connectedNodes + * @param startNode + * @param endNode + * @param distance + * @param minDistance + */ + private static void dfs(List> ladders, Set ladder, Map> connectedNodes, + String startNode, String endNode, int distance, int minDistance) { + if (distance == minDistance && startNode.equals(endNode)) { + ladder.add(endNode); + ladders.add(new ArrayList<>(ladder)); + return; + } else if (distance > minDistance) { + return; + } + + ladder.add(startNode); + for (String nextNode : connectedNodes.getOrDefault(startNode, new HashSet<>())) { + if (!ladder.contains(nextNode)) { + dfs(ladders, new LinkedHashSet<>(ladder), connectedNodes, nextNode, endNode, distance + 1, minDistance); + } + } + } + + public static void main(String[] args) { + assertEquals("[[hit, hot, lot, log, cog], [hit, hot, dot, dog, cog]]", findLadders("hit", "cog", Arrays.asList("hot", "dot", "dog", "lot", "log", "cog")).toString()); + // TODO Fix this test case System.out.println(findLadders("cet", "ism", Arrays.asList("kid", "tag", "pup", "ail", "tun", "woo", "erg", "luz", "brr", "gay", "sip", "kay", "per", "val", "mes", "ohs", "now", "boa", "cet", "pal", "bar", "die", "war", "hay", "eco", "pub", "lob", "rue", "fry", "lit", "rex", "jan", "cot", "bid", "ali", "pay", "col", "gum", "ger", "row", "won", "dan", "rum", "fad", "tut", "sag", "yip", "sui", "ark", "has", "zip", "fez", "own", "ump", "dis", "ads", "max", "jaw", "out", "btu", "ana", "gap", "cry", "led", "abe", "box", "ore", "pig", "fie", "toy", "fat", "cal", "lie", "noh", "sew", "ono", "tam", "flu", "mgm", "ply", "awe", "pry", "tit", "tie", "yet", "too", "tax", "jim", "san", "pan", "map", "ski", "ova", "wed", "non", "wac", "nut", "why", "bye", "lye", "oct", "old", "fin", "feb", "chi", "sap", "owl", "log", "tod", "dot", "bow", "fob", "for", "joe", "ivy", "fan", "age", "fax", "hip", "jib", "mel", "hus", "sob", "ifs", "tab", "ara", "dab", "jag", "jar", "arm", "lot", "tom", "sax", "tex", "yum", "pei", "wen", "wry", "ire", "irk", "far", "mew", "wit", "doe", "gas", "rte", "ian", "pot", "ask", "wag", "hag", "amy", "nag", "ron", "soy", "gin", "don", "tug", "fay", "vic", "boo", "nam", "ave", "buy", "sop", "but", "orb", "fen", "paw", "his", "sub", "bob", "yea", "oft", "inn", "rod", "yam", "pew", "web", "hod", "hun", "gyp", "wei", "wis", "rob", "gad", "pie", "mon", "dog", "bib", "rub", "ere", "dig", "era", "cat", "fox", "bee", "mod", "day", "apr", "vie", "nev", "jam", "pam", "new", "aye", "ani", "and", "ibm", "yap", "can", "pyx", "tar", "kin", "fog", "hum", "pip", "cup", "dye", "lyx", "jog", "nun", "par", "wan", "fey", "bus", "oak", "bad", "ats", "set", "qom", "vat", "eat", "pus", "rev", "axe", "ion", "six", "ila", "lao", "mom", "mas", "pro", "few", "opt", "poe", "art", "ash", "oar", "cap", "lop", "may", "shy", "rid", "bat", "sum", "rim", "fee", "bmw", "sky", "maj", "hue", "thy", "ava", "rap", "den", "fla", "auk", "cox", "ibo", "hey", "saw", "vim", "sec", "ltd", "you", "its", "tat", "dew", "eva", "tog", "ram", "let", "see", "zit", "maw", "nix", "ate", "gig", "rep", "owe", "ind", "hog", "eve", "sam", "zoo", "any", "dow", "cod", "bed", "vet", "ham", "sis", "hex", "via", "fir", "nod", "mao", "aug", "mum", "hoe", "bah", "hal", "keg", "hew", "zed", "tow", "gog", "ass", "dem", "who", "bet", "gos", "son", "ear", "spy", "kit", "boy", "due", "sen", "oaf", "mix", "hep", "fur", "ada", "bin", "nil", "mia", "ewe", "hit", "fix", "sad", "rib", "eye", "hop", "haw", "wax", "mid", "tad", "ken", "wad", "rye", "pap", "bog", "gut", "ito", "woe", "our", "ado", "sin", "mad", "ray", "hon", "roy", "dip", "hen", "iva", "lug", "asp", "hui", "yak", "bay", "poi", "yep", "bun", "try", "lad", "elm", "nat", "wyo", "gym", "dug", "toe", "dee", "wig", "sly", "rip", "geo", "cog", "pas", "zen", "odd", "nan", "lay", "pod", "fit", "hem", "joy", "bum", "rio", "yon", "dec", "leg", "put", "sue", "dim", "pet", "yaw", "nub", "bit", "bur", "sid", "sun", "oil", "red", "doc", "moe", "caw", "eel", "dix", "cub", "end", "gem", "off", "yew", "hug", "pop", "tub", "sgt", "lid", "pun", "ton", "sol", "din", "yup", "jab", "pea", "bug", "gag", "mil", "jig", "hub", "low", "did", "tin", "get", "gte", "sox", "lei", "mig", "fig", "lon", "use", "ban", "flo", "nov", "jut", "bag", "mir", "sty", "lap", "two", "ins", "con", "ant", "net", "tux", "ode", "stu", "mug", "cad", "nap", "gun", "fop", "tot", "sow", "sal", "sic", "ted", "wot", "del", "imp", "cob", "way", "ann", "tan", "mci", "job", "wet", "ism", "err", "him", "all", "pad", "hah", "hie", "aim", "ike", "jed", "ego", "mac", "baa", "min", "com", "ill", "was", "cab", "ago", "ina", "big", "ilk", "gal", "tap", "duh", "ola", "ran", "lab", "top", "gob", "hot", "ora", "tia", "kip", "han", "met", "hut", "she", "sac", "fed", "goo", "tee", "ell", "not", "act", "gil", "rut", "ala", "ape", "rig", "cid", "god", "duo", "lin", "aid", "gel", "awl", "lag", "elf", "liz", "ref", "aha", "fib", "oho", "tho", "her", "nor", "ace", "adz", "fun", "ned", "coo", "win", "tao", "coy", "van", "man", "pit", "guy", "foe", "hid", "mai", "sup", "jay", "hob", "mow", "jot", "are", "pol", "arc", "lax", "aft", "alb", "len", "air", "pug", "pox", "vow", "got", "meg", "zoe", "amp", "ale", "bud", "gee", "pin", "dun", "pat", "ten", "mob"))); + } +} From 3e95cdc9352111af0a408ae6b2c6b023c02001fa Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sat, 17 Aug 2019 19:31:05 +0100 Subject: [PATCH 49/70] IsomorphicStrings: done --- .../java/com/leetcode/graphs/WordLadder.java | 14 +- .../trees/SerializeDeserializeBinaryTree.java | 179 ++++++++++++++++++ 2 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/leetcode/trees/SerializeDeserializeBinaryTree.java diff --git a/src/main/java/com/leetcode/graphs/WordLadder.java b/src/main/java/com/leetcode/graphs/WordLadder.java index 979fb12e..61e706ce 100644 --- a/src/main/java/com/leetcode/graphs/WordLadder.java +++ b/src/main/java/com/leetcode/graphs/WordLadder.java @@ -102,8 +102,20 @@ public static int ladderLength(String beginWord, String endWord, List wo return 0; } + /** + * TODO: Optimized both end BFS solution + * + * @param beginWord + * @param endWord + * @param wordList + * @return + */ + public static int ladderLengthOptimized(String beginWord, String endWord, List wordList) { + return -1; + } + public static void main(String[] args) { assertEquals(5, ladderLength("hit", "cog", Arrays.asList("hot", "dot", "dog", "lot", "log", "cog"))); assertEquals(0, ladderLength("hit", "cog", Arrays.asList("hot", "dot", "dog", "lot", "log"))); } -} +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/trees/SerializeDeserializeBinaryTree.java b/src/main/java/com/leetcode/trees/SerializeDeserializeBinaryTree.java new file mode 100644 index 00000000..690de39d --- /dev/null +++ b/src/main/java/com/leetcode/trees/SerializeDeserializeBinaryTree.java @@ -0,0 +1,179 @@ +package com.leetcode.trees; + + +import java.util.LinkedList; +import java.util.Queue; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/serialize-and-deserialize-binary-tree/ + * Description: + * Serialization is the process of converting a data structure or object into a sequence of bits so that it can be + * stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in + * the same or another computer environment. + * + * Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your + * serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized + * to a string and this string can be deserialized to the original tree structure. + * + * Example: + * + * You may serialize the following tree: + * + * 1 + * / \ + * 2 3 + * / \ + * 4 5 + * + * as "[1,2,3,null,null,4,5]" + * + * Clarification: The above format is the same as how LeetCode serializes a binary tree. You do not necessarily need + * to follow this format, so please be creative and come up with different approaches yourself. + * + * Note: Do not use class member/global/static variables to store states. Your serialize and deserialize algorithms + * should be stateless. + * + * @author rampatra + * @since 2019-08-17 + */ +public class SerializeDeserializeBinaryTree { + + /** + * Runtime: 31 ms. + * + * @param root + * @return + */ + public static String serialize(TreeNode root) { + if (root == null) { + return "[]"; + } + + StringBuilder sb = new StringBuilder(); + sb.append("["); + + Queue queue = new LinkedList<>(); + queue.add(root); + + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + + if (sb.length() > 1) { + sb.append(", "); + } + if (node == null) { + sb.append("null"); + continue; + } + + sb.append(node.val); + + queue.add(node.left); + queue.add(node.right); + } + + sb.append("]"); + return removeExtraNulls(sb.toString()); + } + + private static String removeExtraNulls(String data) { + int i = data.length() - 1; + while (!(data.charAt(i) >= 48 && data.charAt(i) <= 57)) { + i--; + } + return data.substring(0, i + 1) + "]"; + } + + /** + * + * @param data + * @return + */ + public static TreeNode deserialize(String data) { + data = data.substring(1, data.length() - 1); + + if (data.length() == 0) { + return null; + } + + String[] values = data.split(", "); + + TreeNode root = new TreeNode(Integer.parseInt(values[0])); + + Queue queue = new LinkedList<>(); + queue.add(root); + + for (int i = 0; i < values.length && !queue.isEmpty(); i += 2) { + TreeNode currNode = queue.poll(); + + if (i + 1 < values.length && !values[i + 1].equals("null")) { + TreeNode leftNode = new TreeNode(Integer.parseInt(values[i + 1])); + currNode.left = leftNode; + queue.add(leftNode); + } + + if (i + 2 < values.length && !values[i + 2].equals("null")) { + TreeNode rightNode = new TreeNode(Integer.parseInt(values[i + 2])); + currNode.right = rightNode; + queue.add(rightNode); + } + } + + return root; + } + + public static void main(String[] args) { + // TODO Convert the print statements to asserts + + System.out.println(serialize(new TreeNode(1))); + + /* + Binary Tree + + 1 + / \ + 2 3 + / \ + 4 5 + */ + TreeNode tree = new TreeNode(1); + tree.left = new TreeNode(2); + tree.right = new TreeNode(3); + tree.left.left = new TreeNode(4); + tree.left.right = new TreeNode(5); + + System.out.println(serialize(tree)); + + System.out.println(serialize(deserialize(serialize(tree)))); + + System.out.println(serialize(deserialize(serialize(null)))); + + TreeNode tree2 = new TreeNode(1); + tree2.right = new TreeNode(2); + tree2.right.right = new TreeNode(3); + tree2.right.right.right = new TreeNode(4); + tree2.right.right.right.right = new TreeNode(5); + tree2.right.right.right.right.right = new TreeNode(6); + tree2.right.right.right.right.right.right = new TreeNode(7); + tree2.right.right.right.right.right.right.right = new TreeNode(8); + + System.out.println(serialize(tree2)); + System.out.println(serialize(deserialize(serialize(tree2)))); + + System.out.println("---"); + + System.out.println(serialize(deserialize("[1, 2]"))); + System.out.println(serialize(deserialize("[1, 2, 3]"))); + System.out.println(serialize(deserialize("[3, 2, 4, 1]"))); + System.out.println(serialize(deserialize("[3, 2, 4, 1, 5, 6]"))); + System.out.println(serialize(deserialize("[1, 2, 3, null, null, 4, 5]"))); + System.out.println(serialize(deserialize("[5, 2, 3, null, null, 2, 4, 3, 1]"))); + + System.out.println(serialize(deserialize("[1, null, 2, null, 3, null, 4, null, 5]"))); + System.out.println(serialize(deserialize("[1, null, 2, null, 3, null, 4, null, 5, null, 6]"))); + System.out.println(serialize(deserialize("[1, null, 2, null, 3, null, 4, null, 5, null, 6, null, 7]"))); + System.out.println(serialize(deserialize("[1, null, 2, null, 3, null, 4, null, 5, null, 6, null, 7, null, 8]"))); + System.out.println(serialize(deserialize("[1, null, 2, null, 3, null, 4, null, 5, null, 6, null, 7, null, 8, null, 9]"))); + } +} \ No newline at end of file From dfe3fdd68432d226b17f424dd5343e5aca85e73e Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 18 Aug 2019 00:16:35 +0100 Subject: [PATCH 50/70] Exclusive Time Functions: done --- .../stacks/ExclusiveTimeOfFunctions.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java diff --git a/src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java b/src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java new file mode 100644 index 00000000..169f41a2 --- /dev/null +++ b/src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java @@ -0,0 +1,89 @@ +package com.leetcode.stacks; + +import javafx.util.Pair; + +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/exclusive-time-of-functions/ + * Description: + * On a single threaded CPU, we execute some functions. Each function has a unique id between 0 and N-1. + * + * We store logs in timestamp order that describe when a function is entered or exited. + * + * Each log is a string with this format: "{function_id}:{"start" | "end"}:{timestamp}". For example, "0:start:3" + * means the function with id 0 started at the beginning of timestamp 3. "1:end:2" means the function with id 1 ended + * at the end of timestamp 2. + * + * A function's exclusive time is the number of units of time spent in this function. Note that this does not include + * any recursive calls to child functions. + * + * The CPU is single threaded which means that only one function is being executed at a given time unit. + * + * Return the exclusive time of each function, sorted by their function id. + * + * Input: + * n = 2 + * logs = ["0:start:0","1:start:2","1:end:5","0:end:6"] + * Output: [3, 4] + * Explanation: + * Function 0 starts at the beginning of time 0, then it executes 2 units of time and reaches the end of time 1. + * Now function 1 starts at the beginning of time 2, executes 4 units of time and ends at time 5. + * Function 0 is running again at the beginning of time 6, and also ends at the end of time 6, thus executing for 1 unit of time. + * So function 0 spends 2 + 1 = 3 units of total time executing, and function 1 spends 4 units of total time executing. + * + * + * Note: + * -> 1 <= n <= 100 + * -> Two functions won't start or end at the same time. + * -> Functions will always log when they exit. + * + * @author rampatra + * @since 2019-08-17 + */ +public class ExclusiveTimeOfFunctions { + + /** + * Runtime: 18 ms. + * + * @param n + * @param logs + * @return + */ + public static int[] exclusiveTime(int n, List logs) { + int[] times = new int[n]; + Stack> stack = new Stack<>(); + + for (String log : logs) { + String[] l = log.split(":"); + int id = Integer.parseInt(l[0]); + String operation = l[1]; + int timestamp = Integer.parseInt(l[2]); + + if (operation.equals("start")) { + if (!stack.empty()) { + times[stack.peek().getKey()] += (timestamp - stack.peek().getValue() - 1); + } + stack.push(new Pair<>(id, timestamp)); + } else { + times[id] += timestamp - stack.pop().getValue() + 1; + if (!stack.isEmpty()) { + stack.push(new Pair<>(stack.pop().getKey(), timestamp)); + } + } + } + + return times; + } + + public static void main(String[] args) { + assertEquals("[4]", Arrays.toString(exclusiveTime(1, Arrays.asList("0:start:0", "0:start:1", "0:end:2", "0:end:3")))); + assertEquals("[6]", Arrays.toString(exclusiveTime(1, Arrays.asList("0:start:0", "0:start:1", "0:start:2", "0:end:3", "0:end:4", "0:end:5")))); + assertEquals("[3, 4]", Arrays.toString(exclusiveTime(2, Arrays.asList("0:start:0", "1:start:2", "1:end:5", "0:end:6")))); + } +} \ No newline at end of file From 4b89f45be4290f0cb429fb011e122c8942b23e3f Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 18 Aug 2019 20:16:57 +0100 Subject: [PATCH 51/70] Max prod subarray: done --- .../MaximumProductSubArray.java | 62 +++++++++++++++++++ .../MaximumSubArray.java | 2 +- .../stacks/ExclusiveTimeOfFunctions.java | 4 +- 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/leetcode/dynamicprogramming/MaximumProductSubArray.java rename src/main/java/com/leetcode/{arrays => dynamicprogramming}/MaximumSubArray.java (98%) diff --git a/src/main/java/com/leetcode/dynamicprogramming/MaximumProductSubArray.java b/src/main/java/com/leetcode/dynamicprogramming/MaximumProductSubArray.java new file mode 100644 index 00000000..781cad13 --- /dev/null +++ b/src/main/java/com/leetcode/dynamicprogramming/MaximumProductSubArray.java @@ -0,0 +1,62 @@ +package com.leetcode.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/maximum-product-subarray/ + * Description: + * Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which + * has the largest product. + *

+ * Example 1: + * Input: [2,3,-2,4] + * Output: 6 + * Explanation: [2,3] has the largest product 6. + *

+ * Example 2: + * Input: [-2,0,-1] + * Output: 0 + * Explanation: The result cannot be 2, because [-2,-1] is not a subarray. + * + * @author rampatra + * @since 2019-08-18 + */ +public class MaximumProductSubArray { + + /** + * The approach is similar to {@link MaximumSubArray} where we update maxUntilIndex only if multiplying the current + * number to the product of of all numbers until index produces a larger product and if not make maxUntilIndex the + * current number. The only twist here is that we keep two such variables, one for max and one for min, and that's + * because the product of two negatives gives us a positive number. + *

+ * Runtime: 1 ms. + * + * @param nums + * @return + */ + public static int maxProduct(int[] nums) { + int maxProd = nums[0]; + int maxUntilIndex = nums[0]; + int minUntilIndex = nums[0]; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] >= 0) { + maxUntilIndex = Math.max(nums[i], maxUntilIndex * nums[i]); + minUntilIndex = Math.min(nums[i], minUntilIndex * nums[i]); + } else { + int prevMaxUntilIndex = maxUntilIndex; + maxUntilIndex = Math.max(nums[i], minUntilIndex * nums[i]); // when current number is -ve then multiply with minUntilIndex to get the max as product of two negatives is a positive + minUntilIndex = Math.min(nums[i], prevMaxUntilIndex * nums[i]); + } + + maxProd = Math.max(maxProd, maxUntilIndex); + } + + return maxProd; + } + + public static void main(String[] args) { + assertEquals(24, maxProduct(new int[]{-2, 3, -4})); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/MaximumSubArray.java b/src/main/java/com/leetcode/dynamicprogramming/MaximumSubArray.java similarity index 98% rename from src/main/java/com/leetcode/arrays/MaximumSubArray.java rename to src/main/java/com/leetcode/dynamicprogramming/MaximumSubArray.java index f9a64a3f..90a28c93 100644 --- a/src/main/java/com/leetcode/arrays/MaximumSubArray.java +++ b/src/main/java/com/leetcode/dynamicprogramming/MaximumSubArray.java @@ -1,4 +1,4 @@ -package com.leetcode.arrays; +package com.leetcode.dynamicprogramming; /** * Level: Easy diff --git a/src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java b/src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java index 169f41a2..63c61dc2 100644 --- a/src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java +++ b/src/main/java/com/leetcode/stacks/ExclusiveTimeOfFunctions.java @@ -66,13 +66,13 @@ public static int[] exclusiveTime(int n, List logs) { int timestamp = Integer.parseInt(l[2]); if (operation.equals("start")) { - if (!stack.empty()) { + if (!stack.empty()) { // if there are other processes started before, calculate their time until now times[stack.peek().getKey()] += (timestamp - stack.peek().getValue() - 1); } stack.push(new Pair<>(id, timestamp)); } else { times[id] += timestamp - stack.pop().getValue() + 1; - if (!stack.isEmpty()) { + if (!stack.isEmpty()) { // if there are other processes, make their start time to now stack.push(new Pair<>(stack.pop().getKey(), timestamp)); } } From b2aba3e6fcf22bf24ce6b8c3089a372bf7852063 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Sun, 18 Aug 2019 22:37:11 +0100 Subject: [PATCH 52/70] linked list cycle done --- .../linkedlists/LinkedListCycleII.java | 73 +++++++++++++++++++ .../linkedlists/DetectAndRemoveLoop.java | 25 ++++++- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/leetcode/linkedlists/LinkedListCycleII.java diff --git a/src/main/java/com/leetcode/linkedlists/LinkedListCycleII.java b/src/main/java/com/leetcode/linkedlists/LinkedListCycleII.java new file mode 100644 index 00000000..d5fe0e50 --- /dev/null +++ b/src/main/java/com/leetcode/linkedlists/LinkedListCycleII.java @@ -0,0 +1,73 @@ +package com.leetcode.linkedlists; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/linked-list-cycle-ii/ + * Description: + * Given a linked list, return the node where the cycle begins. If there is no cycle, return null. + * + * To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in + * the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list. + * + * Note: Do not modify the linked list. + * + * Example 1: + * + * Input: head = [3,2,0,-4], pos = 1 + * Output: tail connects to node index 1 + * Explanation: There is a cycle in the linked list, where tail connects to the second node. + * + * + * Example 2: + * + * Input: head = [1,2], pos = 0 + * Output: tail connects to node index 0 + * Explanation: There is a cycle in the linked list, where tail connects to the first node. + * + * + * Example 3: + * + * Input: head = [1], pos = -1 + * Output: no cycle + * Explanation: There is no cycle in the linked list. + * + * Follow-up: + * Can you solve it without using extra space? + * + * @author rampatra + * @since 2019-08-18 + */ +public class LinkedListCycleII { + + /** + * Runtime: 0 ms. + * + * @param head + * @return + */ + public Node detectCycle(Node head) { + Node slow = head; + Node fast = head; + + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) { + break; + } + } + + if (fast == null || fast.next == null) { + return null; + } else { + slow = head; + + while (slow != fast) { + slow = slow.next; + fast = fast.next; + } + + return slow; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/rampatra/linkedlists/DetectAndRemoveLoop.java b/src/main/java/com/rampatra/linkedlists/DetectAndRemoveLoop.java index ade19e90..5ad549d4 100644 --- a/src/main/java/com/rampatra/linkedlists/DetectAndRemoveLoop.java +++ b/src/main/java/com/rampatra/linkedlists/DetectAndRemoveLoop.java @@ -34,6 +34,11 @@ public class DetectAndRemoveLoop { * ii. Now, move both slow and fast pointer at same pace and where they meet is the starting point of the loop. * iii. Lastly, to remove the loop make the next of the node (before the starting point of loop) to null. * + * Proof for Floyd's Cycle Detection: Consider a cyclic list and imagine the slow and fast pointers are two runners + * racing around a circle track. The fast runner will eventually meet the slow runner. Why? Consider this case - + * The fast runner is just one step behind the slow runner. In the next iteration, they both increment one and two + * steps respectively and meet each other. + * * @param list * @param * @return {@code true} if loop exists {@code false} otherwise. @@ -58,7 +63,7 @@ public static > boolean detectAndRemoveLoop(SingleLinked while (true) { slow = slow.next; fast = fast.next; - if (slow.next == fast.next) { + if (slow == fast) { fast.next = null; break; } @@ -78,5 +83,23 @@ public static void main(String[] args) { linkedList.getNode(4).next = linkedList.getNode(2); System.out.println(detectAndRemoveLoop(linkedList)); linkedList.printList(); + + linkedList = new SingleLinkedList<>(); + linkedList.add(0); + linkedList.add(1); + linkedList.getNode(1).next = linkedList.getNode(0); + System.out.println(detectAndRemoveLoop(linkedList)); + linkedList.printList(); + + linkedList = new SingleLinkedList<>(); + linkedList.add(0); + System.out.println(detectAndRemoveLoop(linkedList)); + linkedList.printList(); + + linkedList = new SingleLinkedList<>(); + linkedList.add(0); + linkedList.getNode(0).next = linkedList.getNode(0); + System.out.println(detectAndRemoveLoop(linkedList)); + linkedList.printList(); } } \ No newline at end of file From d97139367d39f148b629dd818f3892739dc2ea76 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 19 Aug 2019 17:44:04 +0100 Subject: [PATCH 53/70] topk frequent elements --- .../heaps/KthLargestElementInArray.java | 143 ++++++++++++++++++ .../leetcode/heaps/TopKFrequentElements.java | 68 +++++++++ 2 files changed, 211 insertions(+) create mode 100644 src/main/java/com/leetcode/heaps/KthLargestElementInArray.java create mode 100644 src/main/java/com/leetcode/heaps/TopKFrequentElements.java diff --git a/src/main/java/com/leetcode/heaps/KthLargestElementInArray.java b/src/main/java/com/leetcode/heaps/KthLargestElementInArray.java new file mode 100644 index 00000000..2422de08 --- /dev/null +++ b/src/main/java/com/leetcode/heaps/KthLargestElementInArray.java @@ -0,0 +1,143 @@ +package com.leetcode.heaps; + +import com.rampatra.base.MaxHeap; + +import java.util.PriorityQueue; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/kth-largest-element-in-an-array/ + * Description: + * Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not + * the kth distinct element. + *

+ * Example 1: + * Input: [3,2,1,5,6,4] and k = 2 + * Output: 5 + *

+ * Example 2: + * Input: [3,2,3,1,2,4,5,5,6] and k = 4 + * Output: 4 + *

+ * Note: + * You may assume k is always valid, 1 ≤ k ≤ array's length. + * + * @author rampatra + * @since 2019-08-19 + */ +public class KthLargestElementInArray { + + /** + * Runtime: 1 ms. + * + * @param nums + * @param k + * @return + */ + public static int findKthLargest(int[] nums, int k) { + return heapSortUntilK(nums, k); + } + + /** + * In heapsort, after each iteration we have the max element at the end of the array. Ergo, if we run the algorithm + * k times then we would have our kth largest element. + * + * @param a + * @param k + * @return + */ + public static int heapSortUntilK(int[] a, int k) { + buildMaxHeap(a); + int count = 0; + + for (int i = a.length - 1; i > 0; i--) { + if (count++ == k) { + break; + } + swap(a, 0, i); + maxHeapify(a, 0, i); + } + + return a[a.length - k]; + } + + /** + * Makes the array {@param a} satisfy the max heap property starting from + * {@param index} till {@param end} position in array. + *

+ * See this {@link MaxHeap#maxHeapify} for a basic version of maxHeapify. + *

+ * Time complexity: O(log n). + * + * @param a + * @param index + * @param end + */ + public static void maxHeapify(int[] a, int index, int end) { + int largest = index; + int leftIndex = 2 * index + 1; + int rightIndex = 2 * index + 2; + + if (leftIndex < end && a[index] < a[leftIndex]) { + largest = leftIndex; + } + if (rightIndex < end && a[largest] < a[rightIndex]) { + largest = rightIndex; + } + + if (largest != index) { + swap(a, index, largest); + maxHeapify(a, largest, end); + } + } + + /** + * Converts array {@param a} in to a max heap. + *

+ * Time complexity: O(n) and is not O(n log n). + */ + private static void buildMaxHeap(int[] a) { + for (int i = a.length / 2 - 1; i >= 0; i--) { + maxHeapify(a, i, a.length); + } + } + + + /** + * When you poll() on a PriorityQueue the smallest number in the queue is removed. Based on this property, we can + * iterate over the entire array and in the end we would be left with the k largest element in the queue. + * + * @param nums + * @param k + * @return + */ + public static int findKthLargestUsingPriorityQueue(int[] nums, int k) { + PriorityQueue priorityQueue = new PriorityQueue<>(); + + for (int num : nums) { + priorityQueue.add(num); + + if (priorityQueue.size() > k) { + priorityQueue.poll(); + } + } + + return priorityQueue.isEmpty() ? -1 : priorityQueue.peek(); + } + + private static void swap(int[] a, int firstIndex, int secondIndex) { + a[firstIndex] = a[firstIndex] + a[secondIndex]; + a[secondIndex] = a[firstIndex] - a[secondIndex]; + a[firstIndex] = a[firstIndex] - a[secondIndex]; + } + + public static void main(String[] args) { + assertEquals(5, findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 2)); + assertEquals(3, findKthLargest(new int[]{3, 2, 1, 5, 6, 4}, 4)); + + assertEquals(5, findKthLargestUsingPriorityQueue(new int[]{3, 2, 1, 5, 6, 4}, 2)); + assertEquals(3, findKthLargestUsingPriorityQueue(new int[]{3, 2, 1, 5, 6, 4}, 4)); + } +} diff --git a/src/main/java/com/leetcode/heaps/TopKFrequentElements.java b/src/main/java/com/leetcode/heaps/TopKFrequentElements.java new file mode 100644 index 00000000..5a684325 --- /dev/null +++ b/src/main/java/com/leetcode/heaps/TopKFrequentElements.java @@ -0,0 +1,68 @@ +package com.leetcode.heaps; + +import javafx.util.Pair; + +import java.util.*; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/top-k-frequent-elements/ + * Description: + * Given a non-empty array of integers, return the k most frequent elements. + *

+ * Example 1: + * Input: nums = [1,1,1,2,2,3], k = 2 + * Output: [1,2] + *

+ * Example 2: + * Input: nums = [1], k = 1 + * Output: [1] + *

+ * Note: + * - You may assume k is always valid, 1 ≤ k ≤ number of unique elements. + * - Your algorithm's time complexity must be better than O(n log n), where n is the array's size. + * + * @author rampatra + * @since 2019-08-19 + */ +public class TopKFrequentElements { + + /** + * TODO: A faster approach without using Pair. + *

+ * Runtime: 51 ms. + * + * @param nums + * @param k + * @return + */ + public static List topKFrequent(int[] nums, int k) { + Map numCount = new HashMap<>(); + PriorityQueue> pq = new PriorityQueue<>(Comparator.comparing(Pair::getValue)); + + for (int num : nums) { + numCount.put(num, numCount.getOrDefault(num, 0) + 1); + } + + for (Map.Entry entry : numCount.entrySet()) { + pq.add(new Pair<>(entry.getKey(), entry.getValue())); + + if (pq.size() > k) { + pq.poll(); + } + } + + return pq.stream().map(Pair::getKey).collect(Collectors.toList()); + } + + public static void main(String[] args) { + assertEquals("[2, 1]", topKFrequent(new int[]{1, 1, 1, 2, 2, 3}, 2).toString()); + assertEquals("[0]", topKFrequent(new int[]{3, 0, 1, 0}, 1).toString()); + assertEquals("[1]", topKFrequent(new int[]{1}, 1).toString()); + assertEquals("[1, 2]", topKFrequent(new int[]{1, 2}, 2).toString()); + assertEquals("[2, -1]", topKFrequent(new int[]{4, 1, -1, 2, -1, 2, 3}, 2).toString()); + } +} From 788eb3dec3a1cdb96f25eecf650ccad766079d2c Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Mon, 19 Aug 2019 20:39:53 +0100 Subject: [PATCH 54/70] binary search questions: done --- .../binarysearch/SearchInsertPosition.java | 63 ++++++++++++++ .../SmallestLetterGreaterThanTarget.java | 87 +++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java create mode 100644 src/main/java/com/leetcode/arrays/binarysearch/SmallestLetterGreaterThanTarget.java diff --git a/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java b/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java new file mode 100644 index 00000000..ead76d2a --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java @@ -0,0 +1,63 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Link: https://leetcode.com/problems/search-insert-position/ + * Description: + * Given a sorted array and a target value, return the index if the target is found. If not, return the index where it + * would be if it were inserted in order. + *

+ * You may assume no duplicates in the array. + *

+ * Example 1: + * Input: [1,3,5,6], 5 + * Output: 2 + *

+ * Example 2: + * Input: [1,3,5,6], 2 + * Output: 1 + *

+ * Example 3: + * Input: [1,3,5,6], 7 + * Output: 4 + *

+ * Example 4: + * Input: [1,3,5,6], 0 + * Output: 0 + * + * Similar question: {@link SmallestLetterGreaterThanTarget}. + * + * @author rampatra + * @since 2019-08-19 + */ +public class SearchInsertPosition { + + /** + * Runtime: 0 ms. + * + * @param nums + * @param target + * @return + */ + public static int searchInsert(int[] nums, int target) { + int low = 0; + int high = nums.length - 1; + while (low <= high) { + int mid = low + (high - low) / 2; + if (nums[mid] == target) { + return mid; + } else if (nums[mid] < target) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return low; + } + + public static void main(String[] args) { + assertEquals(2, searchInsert(new int[]{1, 2}, 3)); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/binarysearch/SmallestLetterGreaterThanTarget.java b/src/main/java/com/leetcode/arrays/binarysearch/SmallestLetterGreaterThanTarget.java new file mode 100644 index 00000000..e44dc339 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/SmallestLetterGreaterThanTarget.java @@ -0,0 +1,87 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Link: https://leetcode.com/problems/find-smallest-letter-greater-than-target/ + * Description: + * Given a list of sorted characters letters containing only lowercase letters, and given a target letter target, find + * the smallest element in the list that is larger than the given target. + * + * Letters also wrap around. For example, if the target is target = 'z' and letters = ['a', 'b'], the answer is 'a'. + * + * Examples: + * + * Input: + * letters = ["c", "f", "j"] + * target = "a" + * Output: "c" + * + * Input: + * letters = ["c", "f", "j"] + * target = "c" + * Output: "f" + * + * Input: + * letters = ["c", "f", "j"] + * target = "d" + * Output: "f" + * + * Input: + * letters = ["c", "f", "j"] + * target = "g" + * Output: "j" + * + * Input: + * letters = ["c", "f", "j"] + * target = "j" + * Output: "c" + * + * Input: + * letters = ["c", "f", "j"] + * target = "k" + * Output: "c" + * + * Note: + * - letters has a length in range [2, 10000]. + * - letters consists of lowercase letters, and contains at least 2 unique letters. + * - target is a lowercase letter. + * + * @author rampatra + * @since 2019-08-19 + */ +public class SmallestLetterGreaterThanTarget { + + /** + * Runtime: 0 ms. + * + * @param letters + * @param target + * @return + */ + public static char nextGreatestLetter(char[] letters, char target) { + int low = 0, hi = letters.length - 1; + while (low <= hi) { + int mid = low + (hi - low) / 2; + if (letters[mid] <= target) { + low = mid + 1; + } else { + hi = mid - 1; + } + } + return letters[low % letters.length]; + } + + public static void main(String[] args) { + assertEquals('a', nextGreatestLetter(new char[]{'a'}, 'z')); + assertEquals('b', nextGreatestLetter(new char[]{'a', 'b'}, 'a')); + assertEquals('b', nextGreatestLetter(new char[]{'a', 'b', 'c'}, 'a')); + assertEquals('a', nextGreatestLetter(new char[]{'a', 'b', 'c'}, 'z')); + assertEquals('c', nextGreatestLetter(new char[]{'c', 'f', 'j'}, 'a')); + assertEquals('f', nextGreatestLetter(new char[]{'c', 'f', 'j'}, 'c')); + assertEquals('f', nextGreatestLetter(new char[]{'c', 'f', 'j'}, 'd')); + assertEquals('b', nextGreatestLetter(new char[]{'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}, 'a')); + } +} \ No newline at end of file From 04350de4f583a9d61ea953251dc99f952d12605a Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Tue, 20 Aug 2019 13:30:39 +0100 Subject: [PATCH 55/70] pow x^n : done --- .../leetcode/arrays/binarysearch/PowXN.java | 85 +++++++++++++++++++ .../leetcode/strings/AnagramsInString.java | 2 +- 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/leetcode/arrays/binarysearch/PowXN.java diff --git a/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java b/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java new file mode 100644 index 00000000..b2a305a2 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java @@ -0,0 +1,85 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/powx-n/ + * Description: + * Implement pow(x, n), which calculates x raised to the power n (x^n). + *

+ * Example 1: + * Input: 2.00000, 10 + * Output: 1024.00000 + *

+ * Example 2: + * Input: 2.10000, 3 + * Output: 9.26100 + *

+ * Example 3: + * Input: 2.00000, -2 + * Output: 0.25000 + * Explanation: 2^-2 = 1/22 = 1/4 = 0.25 + *

+ * Note: + * -100.0 < x < 100.0 + * n is a 32-bit signed integer, within the range [−231, 231 − 1] + * + * @author rampatra + * @since 2019-08-19 + */ +public class PowXN { + + /** + * In this approach we iterate n times and keep multiplying x with x. + * Runtime: Time limit exceeded. + * + * @param x + * @param n + * @return + */ + public static double myPowNaive(double x, int n) { + if (n == 0) { + return 1; + } + double res = x; + int absN = Math.abs(n); + for (int i = 1; i < absN; i++) { + res *= x; + } + return n < 0 ? 1 / res : res; + } + + + /** + * In this approach, we iterate log n times. We omit half of n each time. When n is odd, we store whatever product + * we have calculated so far in the final result. + *

+ * Runtime: 1 ms. + * + * @param x + * @param n + * @return + */ + public static double myPow(double x, int n) { + double res = 1; + long absN = Math.abs((long) n); + + while (absN > 0) { + if (absN % 2 == 1) res *= x; // store whatever we have calculated so far in the final result + x *= x; + absN /= 2; + } + return n < 0 ? 1 / res : res; + } + + public static void main(String[] args) { + assertEquals(1024.0, myPowNaive(2.0, 10)); + assertEquals(0.25, myPowNaive(2.0, -2)); + assertEquals(0.0, myPowNaive(0.00001, 2147483647)); + + assertEquals(1024.0, myPow(2.0, 10)); + assertEquals(0.25, myPow(2.0, -2)); + assertEquals(0.0, myPow(0.00001, 2147483647)); + } +} diff --git a/src/main/java/com/leetcode/strings/AnagramsInString.java b/src/main/java/com/leetcode/strings/AnagramsInString.java index afdb3f9f..444fcca4 100644 --- a/src/main/java/com/leetcode/strings/AnagramsInString.java +++ b/src/main/java/com/leetcode/strings/AnagramsInString.java @@ -55,7 +55,7 @@ private static List findAllAnagramsInTextNaive(String text, String patt * where, * n = length of text or number of characters in text *

- * Runtime: 7 ms on leetcode. + * Runtime: 6 ms. * * @param text * @param pattern From a718d3dec8eefec356c3912f210959456cf3e12c Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Tue, 20 Aug 2019 14:08:56 +0100 Subject: [PATCH 56/70] sqrt x: done --- .../leetcode/arrays/binarysearch/PowXN.java | 2 +- .../binarysearch/SearchInsertPosition.java | 3 +- .../leetcode/arrays/binarysearch/SqrtX.java | 62 +++++++++++++++++++ .../leetcode/strings/AnagramsInString.java | 34 +++++++++- 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/leetcode/arrays/binarysearch/SqrtX.java diff --git a/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java b/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java index b2a305a2..3591c50e 100644 --- a/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java +++ b/src/main/java/com/leetcode/arrays/binarysearch/PowXN.java @@ -63,7 +63,7 @@ public static double myPowNaive(double x, int n) { */ public static double myPow(double x, int n) { double res = 1; - long absN = Math.abs((long) n); + long absN = Math.abs((long) n); // used a long so that `absN / 2` doesn't overflow while (absN > 0) { if (absN % 2 == 1) res *= x; // store whatever we have calculated so far in the final result diff --git a/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java b/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java index ead76d2a..2f13214a 100644 --- a/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java +++ b/src/main/java/com/leetcode/arrays/binarysearch/SearchInsertPosition.java @@ -26,7 +26,7 @@ * Example 4: * Input: [1,3,5,6], 0 * Output: 0 - * + *

* Similar question: {@link SmallestLetterGreaterThanTarget}. * * @author rampatra @@ -59,5 +59,6 @@ public static int searchInsert(int[] nums, int target) { public static void main(String[] args) { assertEquals(2, searchInsert(new int[]{1, 2}, 3)); + assertEquals(1, searchInsert(new int[]{1, 3, 5, 6}, 2)); } } \ No newline at end of file diff --git a/src/main/java/com/leetcode/arrays/binarysearch/SqrtX.java b/src/main/java/com/leetcode/arrays/binarysearch/SqrtX.java new file mode 100644 index 00000000..0dde1308 --- /dev/null +++ b/src/main/java/com/leetcode/arrays/binarysearch/SqrtX.java @@ -0,0 +1,62 @@ +package com.leetcode.arrays.binarysearch; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Easy + * Link: https://leetcode.com/problems/sqrtx/ + * Description: + * Implement int sqrt(int x). + * + * Compute and return the square root of x, where x is guaranteed to be a non-negative integer. + * + * Since the return type is an integer, the decimal digits are truncated and only the integer part + * of the result is returned. + * + * Example 1: + * Input: 4 + * Output: 2 + * + * Example 2: + * Input: 8 + * Output: 2 + * Explanation: The square root of 8 is 2.82842..., and since + * the decimal part is truncated, 2 is returned. + * + * @author rampatra + * @since 2019-08-19 + */ +public class SqrtX { + + /** + * Runtime: 1 ms. + * + * @param x + * @return + */ + public static int mySqrt(int x) { + if (x == 0 || x == 1) { + return x; + } + long low = 1; + long high = x / 2; + + while (low <= high) { + long mid = low + (high - low) / 2; + if (mid * mid == x) { + return (int) mid; + } else if (mid * mid < x) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return (int) high; + } + + public static void main(String[] args) { + assertEquals(2, mySqrt(8)); + assertEquals(3, mySqrt(9)); + assertEquals(46339, mySqrt(2147395599)); + } +} \ No newline at end of file diff --git a/src/main/java/com/leetcode/strings/AnagramsInString.java b/src/main/java/com/leetcode/strings/AnagramsInString.java index 444fcca4..12e7d766 100644 --- a/src/main/java/com/leetcode/strings/AnagramsInString.java +++ b/src/main/java/com/leetcode/strings/AnagramsInString.java @@ -5,8 +5,40 @@ import java.util.List; /** - * Level: Easy + * Level: Medium * Problem: https://leetcode.com/problems/find-all-anagrams-in-a-string/ + * Description: + * 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". + * + * Example 2: + * + * Input: + * s: "abab" p: "ab" + * + * Output: + * [0, 1, 2] + * + * Explanation: + * The substring with start index = 0 is "ab", which is an anagram of "ab". + * The substring with start index = 1 is "ba", which is an anagram of "ab". + * The substring with start index = 2 is "ab", which is an anagram of "ab". * * @author rampatra * @since 2019-04-13 From 9a10dadd404b2d0b441e43304223fa0bca5eb8d6 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Tue, 20 Aug 2019 21:10:06 +0100 Subject: [PATCH 57/70] lfu cache: 90% done --- .../java/com/leetcode/design/LFUCache.java | 127 ++++++++++++++++++ .../com/rampatra/linkedlists/LRUCache.java | 16 ++- 2 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/leetcode/design/LFUCache.java diff --git a/src/main/java/com/leetcode/design/LFUCache.java b/src/main/java/com/leetcode/design/LFUCache.java new file mode 100644 index 00000000..0a3e9b8e --- /dev/null +++ b/src/main/java/com/leetcode/design/LFUCache.java @@ -0,0 +1,127 @@ +package com.leetcode.design; + +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Hard + * Link: https://leetcode.com/problems/lfu-cache/ + * Description: + * Design and implement a data structure for Least Frequently Used (LFU) cache. It should support the following + * operations: get and put. + * + * get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. + * put(key, value) - Set or insert the value if the key is not already present. When the cache reaches its capacity, it + * should invalidate the least frequently used item before inserting a new item. For the purpose of this problem, when + * there is a tie (i.e., two or more keys that have the same frequency), the least recently used key would be evicted. + * + * Follow up: + * Could you do both operations in O(1) time complexity? + * + * Note: + * - + * + * @author rampatra + * @since 2019-08-20 + */ +public class LFUCache { + + private int minCount = 0; + private int capacity; + private Map keyValueMap; + private Map keyCountMap; + private Map> countKeysMap; + + + public LFUCache(int capacity) { + this.capacity = capacity; + keyValueMap = new HashMap<>(); + keyCountMap = new HashMap<>(); + countKeysMap = new HashMap<>(); + } + + + public int get(int key) { + Integer val = keyValueMap.get(key); + if (val == null) { + return -1; + } + + int prevCount = keyCountMap.get(key); + countKeysMap.getOrDefault(prevCount, new LinkedHashSet<>()).remove(key); + countKeysMap.putIfAbsent(prevCount + 1, new LinkedHashSet<>()); + countKeysMap.get(prevCount + 1).add(key); + + if (prevCount == minCount && countKeysMap.get(prevCount).size() == 0) { + minCount++; + } + + return val; + } + + + public void put(int key, int value) { + if (capacity <= 0) { + return; + } + + if (!keyValueMap.containsKey(key) && keyCountMap.size() == capacity) { + int keyToEvict = countKeysMap.get(minCount).iterator().next(); + countKeysMap.get(minCount).remove(keyToEvict); + keyValueMap.remove(keyToEvict); + keyCountMap.remove(keyToEvict); + } + + keyValueMap.put(key, value); + int prevCount = keyCountMap.getOrDefault(key, 0); + keyCountMap.put(key, 1); + + countKeysMap.getOrDefault(prevCount, new LinkedHashSet<>()).remove(key); + countKeysMap.putIfAbsent(1, new LinkedHashSet<>()); + countKeysMap.get(1).add(key); + + minCount = 1; + } + + + public static void main(String[] args) { + LFUCache lfuCache = new LFUCache(2); + lfuCache.put(2, 2); + lfuCache.put(3, 3); + lfuCache.put(4, 4); + assertEquals(-1, lfuCache.get(2)); + assertEquals(3, lfuCache.get(3)); + lfuCache.put(5, 5); + assertEquals(-1, lfuCache.get(4)); + + lfuCache = new LFUCache(2); + lfuCache.put(3, 1); + lfuCache.put(2, 1); + lfuCache.put(2, 2); + lfuCache.put(4, 4); + assertEquals(-1, lfuCache.get(3)); + assertEquals(2, lfuCache.get(2)); + + lfuCache = new LFUCache(2); + lfuCache.put(2, 1); + lfuCache.put(2, 2); + assertEquals(2, lfuCache.get(2)); + lfuCache.put(1, 1); + lfuCache.put(4, 4); + assertEquals(2, lfuCache.get(2)); + + lfuCache = new LFUCache(2); + assertEquals(-1, lfuCache.get(2)); + lfuCache.put(2, 6); + assertEquals(-1, lfuCache.get(1)); + lfuCache.put(1, 1); + lfuCache.put(1, 2); + assertEquals(2, lfuCache.get(1)); + assertEquals(6, lfuCache.get(2)); + + // todo fix some test cases https://leetcode.com/submissions/detail/253376947/ + } +} \ No newline at end of file diff --git a/src/main/java/com/rampatra/linkedlists/LRUCache.java b/src/main/java/com/rampatra/linkedlists/LRUCache.java index 5a8d12f1..ed046035 100644 --- a/src/main/java/com/rampatra/linkedlists/LRUCache.java +++ b/src/main/java/com/rampatra/linkedlists/LRUCache.java @@ -2,6 +2,7 @@ import java.util.Iterator; import java.util.LinkedHashMap; +import java.util.LinkedHashSet; import java.util.Map; /** @@ -20,7 +21,7 @@ */ public class LRUCache { - LinkedHashMap linkedHashMap; + private LinkedHashMap linkedHashMap; // initialize cache LRUCache(final int size) { @@ -37,7 +38,7 @@ V add(E key, V value) { } V get(E key) { - return linkedHashMap.get(key); + return linkedHashMap.get(key); } private void print() { @@ -52,12 +53,13 @@ public static void main(String[] args) { cache.add(1, 1); cache.add(2, 2); cache.add(3, 3); + cache.print(); // initial cache contents + + cache.add(4, 4); // should remove 1 as it was accessed last cache.print(); - if (cache.get(4) == null) { - cache.add(4, 4); - } - cache.print(); - cache.add(5, 5); + + cache.get(2); + cache.add(5, 5); // should remove 3 as 2 was recently accessed cache.print(); } } From 27a92f7a20c771a41facd1aedc5f96061d16cb7a Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Tue, 20 Aug 2019 21:38:36 +0100 Subject: [PATCH 58/70] lru cache: done --- .../java/com/leetcode/design/LFUCache.java | 2 +- .../java/com/leetcode/design/LRUCache.java | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/leetcode/design/LRUCache.java diff --git a/src/main/java/com/leetcode/design/LFUCache.java b/src/main/java/com/leetcode/design/LFUCache.java index 0a3e9b8e..595b5a52 100644 --- a/src/main/java/com/leetcode/design/LFUCache.java +++ b/src/main/java/com/leetcode/design/LFUCache.java @@ -22,7 +22,7 @@ * Could you do both operations in O(1) time complexity? * * Note: - * - + * - When setting a key which is already present, reset its frequency/count to 1. * * @author rampatra * @since 2019-08-20 diff --git a/src/main/java/com/leetcode/design/LRUCache.java b/src/main/java/com/leetcode/design/LRUCache.java new file mode 100644 index 00000000..162889f2 --- /dev/null +++ b/src/main/java/com/leetcode/design/LRUCache.java @@ -0,0 +1,61 @@ +package com.leetcode.design; + +import java.util.LinkedHashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * Level: Medium + * Link: https://leetcode.com/problems/lru-cache/ + * Description: + * Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following + * operations: get and put. + * + * get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1. + * put(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it + * should invalidate the least recently used item before inserting a new item. + * + * The cache is initialized with a positive capacity. + * + * Follow up: + * Could you do both operations in O(1) time complexity? + * + * Runtime: 54 ms. + * + * @author rampatra + * @since 2019-08-20 + */ +public class LRUCache { + + private LinkedHashMap cache; + + public LRUCache(int capacity) { + this.cache = new LinkedHashMap(capacity, 0.75f, true) { + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { + return size() > capacity; + } + }; + } + + public int get(int key) { + Integer val = cache.get(key); + return val == null ? -1 : val; + } + + public void put(int key, int value) { + cache.put(key, value); + } + + public static void main(String[] args) { + LRUCache cache = new LRUCache(2); + cache.put(1,1); + cache.put(2,2); + cache.put(1,1); + cache.put(3,3); + assertEquals(1, cache.get(1)); + assertEquals(-1, cache.get(2)); + assertEquals(3, cache.get(3)); + } +} \ No newline at end of file From 142a8495ff206f860a0c1ab9a91773a4d8fac439 Mon Sep 17 00:00:00 2001 From: Ram Patra Date: Wed, 21 Aug 2019 13:59:15 +0100 Subject: [PATCH 59/70] minor refactorings --- .../treesandgraphs/FirstCommonAncestor.java | 5 +++- .../com/leetcode/arrays/BuySellStocks.java | 22 +++++++++++++++++- .../com/leetcode/arrays/BuySellStocksII.java | 4 ++-- .../com/leetcode/arrays/MergeSortedArray.java | 15 +++++++++++- .../java/com/leetcode/arrays/RotateArray.java | 23 ++++++++++++++++++- 5 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/ctci/treesandgraphs/FirstCommonAncestor.java b/src/main/java/com/ctci/treesandgraphs/FirstCommonAncestor.java index f1fc5293..38977be3 100644 --- a/src/main/java/com/ctci/treesandgraphs/FirstCommonAncestor.java +++ b/src/main/java/com/ctci/treesandgraphs/FirstCommonAncestor.java @@ -5,6 +5,9 @@ * tree. Avoid storing additional nodes in a data structure. Also, for this question, the tree node * does NOT have access to its parent node. NOTE: This is not necessarily a binary search tree. * + * First Common Ancestor or the Least/Lowest Common Ancestor of two nodes is a node which is the + * closest to both of the nodes. + * * @author rampatra * @since 2019-02-24 */ @@ -18,7 +21,7 @@ public class FirstCommonAncestor { * - Returns null, if neither p nor q are in root's subtree. * - Else, returns the common ancestor of p and q. *

- * See {@link com.rampatra.trees.LeastCommonAncestorInBT} for a simpler version. + * See {@link com.rampatra.trees.LeastCommonAncestorInBT} for a better answer. * * @param root * @param a diff --git a/src/main/java/com/leetcode/arrays/BuySellStocks.java b/src/main/java/com/leetcode/arrays/BuySellStocks.java index d94c3296..4d4ba02b 100644 --- a/src/main/java/com/leetcode/arrays/BuySellStocks.java +++ b/src/main/java/com/leetcode/arrays/BuySellStocks.java @@ -2,7 +2,27 @@ /** * Level: Easy - * Problem: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ + * Link: https://leetcode.com/problems/best-time-to-buy-and-sell-stock/ + * Description: + * Say you have an array for which the ith element is the price of a given stock on day i. + * + * If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), + * design an algorithm to find the maximum profit. + * + * Note that you cannot sell a stock before you buy one. + * + * Example 1: + * + * Input: [7,1,5,3,6,4] + * Output: 5 + * Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5. + * Not 7-1 = 6, as selling price needs to be larger than buying price. + * + * Example 2: + * + * Input: [7,6,4,3,1] + * Output: 0 + * Explanation: In this case, no transaction is done, i.e. max profit = 0. * * @author rampatra * @since 2019-04-23 diff --git a/src/main/java/com/leetcode/arrays/BuySellStocksII.java b/src/main/java/com/leetcode/arrays/BuySellStocksII.java index 47966b48..d215246e 100644 --- a/src/main/java/com/leetcode/arrays/BuySellStocksII.java +++ b/src/main/java/com/leetcode/arrays/BuySellStocksII.java @@ -2,8 +2,8 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ - * Problem Description: + * Link: https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/ + * Description: * Say you have an array for which the ith element is the price of a given stock on day i. *

* Design an algorithm to find the maximum profit. You may complete as many transactions as you diff --git a/src/main/java/com/leetcode/arrays/MergeSortedArray.java b/src/main/java/com/leetcode/arrays/MergeSortedArray.java index 09cd730d..975db8ec 100644 --- a/src/main/java/com/leetcode/arrays/MergeSortedArray.java +++ b/src/main/java/com/leetcode/arrays/MergeSortedArray.java @@ -4,7 +4,20 @@ /** * Level: Easy - * Problem Link: https://leetcode.com/problems/merge-sorted-array/ + * Link: https://leetcode.com/problems/merge-sorted-array/ + * Description: + * Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array. + * + * Note: + * The number of elements initialized in nums1 and nums2 are m and n respectively. + * You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold + * additional elements from nums2. + * + * Example: + * Input: + * nums1 = [1,2,3,0,0,0], m = 3 + * nums2 = [2,5,6], n = 3 + * Output: [1,2,2,3,5,6] * * @author rampatra * @since 2019-04-26 diff --git a/src/main/java/com/leetcode/arrays/RotateArray.java b/src/main/java/com/leetcode/arrays/RotateArray.java index e4f6de33..91475160 100644 --- a/src/main/java/com/leetcode/arrays/RotateArray.java +++ b/src/main/java/com/leetcode/arrays/RotateArray.java @@ -4,7 +4,28 @@ /** * Level: Easy - * Problem: https://leetcode.com/problems/rotate-array/ + * Link: https://leetcode.com/problems/rotate-array/ + * Description: + * Given an array, rotate the array to the right by k steps, where k is non-negative. + * + * Example 1: + * Input: [1,2,3,4,5,6,7] and k = 3 + * Output: [5,6,7,1,2,3,4] + * Explanation: + * rotate 1 steps to the right: [7,1,2,3,4,5,6] + * rotate 2 steps to the right: [6,7,1,2,3,4,5] + * rotate 3 steps to the right: [5,6,7,1,2,3,4] + * + * Example 2: + * Input: [-1,-100,3,99] and k = 2 + * Output: [3,99,-1,-100] + * Explanation: + * rotate 1 steps to the right: [99,-1,-100,3] + * rotate 2 steps to the right: [3,99,-1,-100] + * + * Note: + * Try to come up as many solutions as you can, there are at least 3 different ways to solve this problem. + * Could you do it in-place with O(1) extra space? * * @author rampatra * @since 2019-04-20 From 497e46319c0bbab7f106d8a03bf47f357dcfa29b Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Thu, 16 Jul 2020 09:09:21 +0100 Subject: [PATCH 60/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 989a3224..58fe8ecb 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The repo consists of solutions to numerous problems using different data structu contains solutions to HackerRank problems which I have solved so far and questions from Cracking the Coding Interview Book _(6th Edition)_. -You can also refer to my [Java Notes](http://java.ramswaroop.me) for a quick refresh on the Java concepts. +You can also refer to my [Java Notes](http://blog.rampatra.com/category/java) for a quick refresh on the Java concepts. ## Contents From 9d705a5a9818ecb5c23b475791826896dba74d2b Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Sat, 20 Feb 2021 08:38:49 +0000 Subject: [PATCH 61/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 58fe8ecb..06b6d7b6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The repo consists of solutions to numerous problems using different data structu contains solutions to HackerRank problems which I have solved so far and questions from Cracking the Coding Interview Book _(6th Edition)_. -You can also refer to my [Java Notes](http://blog.rampatra.com/category/java) for a quick refresh on the Java concepts. +You can also refer to my [Java Notes](http://blog.rampatra.com/category/java) for a quick refresh on the Java concepts. Lastly, feel free to connect with me on [Twitter](https://twitter.com/ram__patra) for any queries or concerns. All the best! ## Contents From 8423f8164cd1ea0acd729d3725b7e70efc0f1e4e Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Mon, 28 Mar 2022 20:34:56 +0100 Subject: [PATCH 62/70] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 06b6d7b6..e6ae9ca8 100644 --- a/README.md +++ b/README.md @@ -50,3 +50,5 @@ IntelliJ IDEA 2018.1.4 (Ultimate Edition) MacBook Pro 2.5 GHz Intel Core i7 16 GB 1600 MHz DDR3 + +_P.S. If my open-source project(s) benefitted you in some way or the other, a follow on [Twitter](https://twitter.com/ram__patra) would be greatly appreciated 🙇‍♂️._ From 7550901537074d35adb0eef09138383c9e162fd0 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Mon, 28 Mar 2022 20:40:27 +0100 Subject: [PATCH 63/70] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e6ae9ca8..0bf98d9d 100644 --- a/README.md +++ b/README.md @@ -51,4 +51,6 @@ MacBook Pro 2.5 GHz Intel Core i7 16 GB 1600 MHz DDR3 +--- + _P.S. If my open-source project(s) benefitted you in some way or the other, a follow on [Twitter](https://twitter.com/ram__patra) would be greatly appreciated 🙇‍♂️._ From 82ae2fd7fc1f364a67e716d7f70ba6289f2357e6 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Sun, 19 Jun 2022 12:42:01 +0100 Subject: [PATCH 64/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bf98d9d..7be895d1 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ MacBook Pro --- -_P.S. If my open-source project(s) benefitted you in some way or the other, a follow on [Twitter](https://twitter.com/ram__patra) would be greatly appreciated 🙇‍♂️._ +_P.S. For any queries or concerns, [Twitter](https://twitter.com/ram__patra) is the best place to reach out to me. I'll try my best to help._ From 87c869ba97e5c18ff111ce5394323b872be5a3b9 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Sun, 19 Jun 2022 12:49:02 +0100 Subject: [PATCH 65/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7be895d1..ce82e09f 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ MacBook Pro --- -_P.S. For any queries or concerns, [Twitter](https://twitter.com/ram__patra) is the best place to reach out to me. I'll try my best to help._ +_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/ram__patra). I'll try my best to help 🙏._ From db15c1e0450c801aa3ee56e0d930fa3e33e3fb62 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Sat, 6 Aug 2022 12:54:42 +0100 Subject: [PATCH 66/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ce82e09f..57f6c1b7 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The repo consists of solutions to numerous problems using different data structu contains solutions to HackerRank problems which I have solved so far and questions from Cracking the Coding Interview Book _(6th Edition)_. -You can also refer to my [Java Notes](http://blog.rampatra.com/category/java) for a quick refresh on the Java concepts. Lastly, feel free to connect with me on [Twitter](https://twitter.com/ram__patra) for any queries or concerns. All the best! +You can also refer to my [Java Notes](http://blog.rampatra.com/category/java) for a quick refresh on the Java concepts or if you want a break from coding then can read about my [interview experiences](https://blog.rampatra.com/category/interview/) at various companies. Lastly, feel free to connect with me on [Twitter](https://twitter.com/ram__patra) for any queries or concerns. All the best! ## Contents From 957d03bfde64f6a2a0a2ba7334d6e2a3ff2a43e9 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Wed, 12 Oct 2022 10:50:00 +0100 Subject: [PATCH 67/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 57f6c1b7..b1bbc14c 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ MacBook Pro --- -_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/ram__patra). I'll try my best to help 🙏._ +_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/ram__patra). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentify.compzets.com)._ From 615e19b8ee550d117308e5df0fc790731710ffa4 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Wed, 17 Jul 2024 19:37:56 +0100 Subject: [PATCH 68/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b1bbc14c..07ebdb73 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ MacBook Pro --- -_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/ram__patra). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentify.compzets.com)._ +_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/ram__patra). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentifyapp.com), or [ToDoBar](https://todobarapp.com/)._ From 7eadd472a3578984626c4d31fec840ecead6fd28 Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:12:11 +0000 Subject: [PATCH 69/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 07ebdb73..195f3c39 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ MacBook Pro --- -_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/ram__patra). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentifyapp.com), or [ToDoBar](https://todobarapp.com/)._ +_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/rampatra_). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentifyapp.com), [FaceScreen](https://facescreenapp.com/), or [ToDoBar](https://todobarapp.com/)._ From c23f98b7f70ab7ca613c34672eeaca8b38c7c43b Mon Sep 17 00:00:00 2001 From: Ram <2862724+rampatra@users.noreply.github.com> Date: Mon, 7 Apr 2025 15:38:06 +0100 Subject: [PATCH 70/70] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 195f3c39..33b68334 100644 --- a/README.md +++ b/README.md @@ -53,4 +53,4 @@ MacBook Pro --- -_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/rampatra_). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentifyapp.com), [FaceScreen](https://facescreenapp.com/), or [ToDoBar](https://todobarapp.com/)._ +_P.S. For any queries or concerns, you can reach out to me on [Twitter](https://twitter.com/rampatra_). I'll try my best to help 🙏. And, if you're keen to know what I'm currently working on then check out [Presentify](https://presentifyapp.com), [FaceScreen](https://facescreenapp.com/), [ToDoBar](https://todobarapp.com/), [SimpleFill](https://simplefillapp.com/), and [Apps.Deals](https://www.apps.deals)._