allNodes = new HashMap<>();
-
- protected void makeNode(Vertex vertex) {
- Node node = new Node(vertex.id);
- node.parent = node;
- allNodes.put(vertex.id, node);
- }
-
- public boolean unionSet(Edge edge) {
- Node srcNode = allNodes.get(edge.vertex1.data);
- Node destNode = allNodes.get(edge.vertex2.data);
-
- Node parentSrcNode = findParent(srcNode);
- Node parentDestNode = findParent(destNode);
-
- if (parentSrcNode != parentDestNode) {
- parentDestNode.parent = parentSrcNode;
- return true;
- }
- return false;
- }
-
- public Node findParent(Node node) {
- Node parent = node.parent;
- if (parent == node) {
- return node;
- }
- return findParent(node.parent);
- }
-}
-
-class Node {
- long data;
- Node parent;
- Node child;
-
- public Node(long id) {
- this.data = id;
- }
-}
diff --git a/src/geeksforgeeks/NextGreaterElement.java b/src/geeksforgeeks/NextGreaterElement.java
deleted file mode 100644
index 6128470..0000000
--- a/src/geeksforgeeks/NextGreaterElement.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Stack;
-
-/**
- * https://www.geeksforgeeks.org/next-greater-element/
- *
- * https://www.geeksforgeeks.org/find-next-greater-number-set-digits/
- */
-class NextGreaterElement {
-
- static int arr[] = {4, 5, 2, 25};
-
- // 9,1,2,3,4,5,6,7
- public static void printNGE() {
- Stack s = new Stack<>();
- int[] nge = new int[arr.length];
-
- for (int i = arr.length - 1; i >= 0; i--) {
-
- while (!s.empty() && s.peek() <= arr[i]) {
- s.pop();
- }
- nge[i] = s.empty() ? -1 : s.peek();
- s.push(arr[i]);
-
- }
- for (int i = 0; i < arr.length; i++)
- System.out.println(arr[i] + " --> " + nge[i]);
-
- }
-
- public static void main(String[] args) {
- printNGE();
- }
-}
diff --git a/src/geeksforgeeks/NextGreaterNumber.java b/src/geeksforgeeks/NextGreaterNumber.java
deleted file mode 100644
index 7278dd9..0000000
--- a/src/geeksforgeeks/NextGreaterNumber.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Arrays;
-
-/**
- * https://www.geeksforgeeks.org/find-next-greater-number-set-digits/
- *
- * https://www.ideserve.co.in/learn/next-greater-number-using-same-digits
- */
-public class NextGreaterNumber {
-
- private void swap(int[] number, int i, int j) {
- int temp = number[i];
- number[i] = number[j];
- number[j] = temp;
- }
-
- private void sortSubarray(int[] number, int i, int j) {
- // for this sub-array, all the digits would be in there reverse sorted position
- while (i < j) {
- swap(number, i, j);
- i += 1;
- j -= 1;
- }
- }
-
- public void findNextGreaterNumber(int[] number) {
- int lastDigitSeen = number[number.length - 1];
- int i;
- int j;
- for (i = number.length - 2; i >= 0; i--) {
- // if this digit is where the sorted ordering breaks
- if (lastDigitSeen > number[i]) {
- break;
- }
- lastDigitSeen = number[i];
- }
-
- if (i >= 0) // we found the digit breaking the sorted ordering
- {
- // find the next greater digit in the right sub-array from number[i+1 to end]
- for (j = number.length - 1; j > i; j--) {
- if (number[j] > number[i]) {
- break;
- }
- }
-
- // swap digits at indices 'i' and 'j'
- swap(number, i, j);
- System.out.println(Arrays.toString(number));
- // sort the sub-array - number[i+1 to end]
- sortSubarray(number, i + 1, number.length - 1);
- }
- }
-
- public static void main(String[] args) {
- NextGreaterNumber solution = new NextGreaterNumber();
-
- int[] number = {6, 9, 3, 8, 6, 5, 2};
- // 6938652
- // 6983652
- // 6982356
- // i =3
-
- solution.findNextGreaterNumber(number);
-
- System.out.println("Next greater number is: ");
- for (int i = 0; i < number.length; i++) {
- System.out.print(number[i]);
- }
- }
-}
diff --git a/src/geeksforgeeks/NonDecreasingArray.java b/src/geeksforgeeks/NonDecreasingArray.java
deleted file mode 100644
index b24d1f2..0000000
--- a/src/geeksforgeeks/NonDecreasingArray.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package geeksforgeeks;
-
-/**
- * https://leetcode.com/problems/non-decreasing-array/description/
- */
-class NonDecreasingArray {
- public boolean checkPossibility(int[] nums) {
-
- int count = 0;
- for (int i = 1; i < nums.length && count <= 1; i++) {
- if (nums[i - 1] > nums[i]) {
- count++;
- if ((i - 2 < 0) || nums[i - 2] <= nums[i]) {
- nums[i - 1] = nums[i];
- } else {
- nums[i] = nums[i - 1];
- }
- }
- }
- return count <= 1;
- }
-
- public static void main(String[] args) {
- // 1,4,2,3
- //3,4,2,3
- int[] nums = {7, 8, 2, 3};
- NonDecreasingArray nda = new NonDecreasingArray();
- System.out.println(nda.checkPossibility(nums));
- }
-}
diff --git a/src/geeksforgeeks/NutsAndBoltsMatch.java b/src/geeksforgeeks/NutsAndBoltsMatch.java
deleted file mode 100644
index 95800bb..0000000
--- a/src/geeksforgeeks/NutsAndBoltsMatch.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package geeksforgeeks;
-
-// Java program to solve nut and bolt problem using Quick Sort
-// unresolved
-public class NutsAndBoltsMatch {
- public static void main(String[] args) {
- // Nuts and bolts are represented as array of characters
- char nuts[] = {'@', '#', '$', '%', '^', '&'};
- char bolts[] = {'$', '%', '&', '^', '@', '#'};
-
- // Method based on quick sort which matches nuts and bolts
- matchPairs(nuts, bolts, 0, 5);
-
- System.out.println("Matched nuts and bolts are : ");
- printArray(nuts);
- printArray(bolts);
- }
-
- // Method to print the array
- private static void printArray(char[] arr) {
- for (char ch : arr) {
- System.out.print(ch + " ");
- }
- System.out.print("n");
- }
-
- // Method which works just like quick sort
- private static void matchPairs(char[] nuts, char[] bolts, int low,
- int high) {
- if (low < high) {
- // Choose last character of bolts array for nuts partition.
- int pivot = partition(nuts, low, high, bolts[high]);
-
- // Now using the partition of nuts choose that for bolts
- // partition.
- partition(bolts, low, high, nuts[pivot]);
-
- // Recur for [low...pivot-1] & [pivot+1...high] for nuts and
- // bolts array.
- matchPairs(nuts, bolts, low, pivot - 1);
- matchPairs(nuts, bolts, pivot + 1, high);
- }
- }
-
- // Similar to standard partition method. Here we pass the pivot element
- // too instead of choosing it inside the method.
- private static int partition(char[] arr, int low, int high, char pivot) {
- int i = low;
- char temp1, temp2;
- for (int j = low; j < high; j++) {
- if (arr[j] < pivot) {
- temp1 = arr[i];
- arr[i] = arr[j];
- arr[j] = temp1;
- i++;
- } else if (arr[j] == pivot) {
- temp1 = arr[j];
- arr[j] = arr[high];
- arr[high] = temp1;
- j--;
- }
- }
- temp2 = arr[i];
- arr[i] = arr[high];
- arr[high] = temp2;
-
- // Return the partition index of an array based on the pivot
- // element of other array.
- return i;
- }
-}
diff --git a/src/geeksforgeeks/OwnDataStructureUtil.java b/src/geeksforgeeks/OwnDataStructureUtil.java
deleted file mode 100644
index 6ffe412..0000000
--- a/src/geeksforgeeks/OwnDataStructureUtil.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package geeksforgeeks;
-
-import java.util.*;
-
-class OwnDataStructureUtil {
- ArrayList list;
- HashMap map;
- java.util.Random rand = new java.util.Random();
-
- public OwnDataStructureUtil() {
- list = new ArrayList<>();
- map = new HashMap<>();
- }
-
- public boolean insert(int val) {
- if (map.containsKey(val))
- return false;
- map.put(val, list.size());
- list.add(val);
- return true;
- }
-
- public boolean remove(int val) {
- if (!map.containsKey(val))
- return false;
- int loc = map.get(val);
- if (loc < list.size() - 1) { // not the last one than swap the last one with this val
- int lastOne = list.get(list.size() - 1);
- list.set(loc, lastOne);
- map.put(lastOne, loc);
- }
- map.remove(val);
- list.remove(list.size() - 1);
- return true;
- }
-
- public int getRandom() {
- return list.get(rand.nextInt(list.size()));
- }
-
- public static void main(String[] args) {
- OwnDataStructureUtil ds = new OwnDataStructureUtil();
- ds.insert(10);
- ds.insert(20);
- ds.insert(30);
- ds.insert(40);
- ds.remove(20);
- ds.insert(50);
- System.out.println(ds.getRandom());
- }
-}
diff --git a/src/geeksforgeeks/PalindromeSinglyLinkedList.java b/src/geeksforgeeks/PalindromeSinglyLinkedList.java
deleted file mode 100644
index 9c51c27..0000000
--- a/src/geeksforgeeks/PalindromeSinglyLinkedList.java
+++ /dev/null
@@ -1,61 +0,0 @@
-package geeksforgeeks;
-
-public class PalindromeSinglyLinkedList {
-
- class Node {
- int data;
- Node next;
-
- public Node(int data) {
- this.data = data;
- }
-
- }
-
- public static void main(String[] args) {
-
- PalindromeSinglyLinkedList palindrome = new PalindromeSinglyLinkedList();
- Node head = palindrome.new Node(1);
- head.next = palindrome.new Node(2);
- head.next.next = palindrome.new Node(3);
- head.next.next.next = palindrome.new Node(2);
- head.next.next.next.next = palindrome.new Node(1);
-
- System.out.println(palindrome.isPalindrome(head));
-
- }
-
- public boolean isPalindrome(Node head) {
- Node fast = head, slow = head;
- while (fast != null && fast.next != null) {
- fast = fast.next.next;
- slow = slow.next;
- }
- if (fast != null) { // odd nodes: let right half smaller
- slow = slow.next;
- }
- slow = reverse(slow);
- fast = head;
-
- while (slow != null) {
- if (fast.data != slow.data) {
- return false;
- }
- fast = fast.next;
- slow = slow.next;
- }
- return true;
- }
-
- public Node reverse(Node head) {
- Node prev = null;
- while (head != null) {
- Node next = head.next;
- head.next = prev;
- prev = head;
- head = next;
- }
- return prev;
- }
-
-}
diff --git a/src/geeksforgeeks/PartitionLabel.java b/src/geeksforgeeks/PartitionLabel.java
deleted file mode 100644
index c5f7d31..0000000
--- a/src/geeksforgeeks/PartitionLabel.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package geeksforgeeks;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class PartitionLabel {
- public List partitionLabels(String S) {
- int[] last = new int[26];
- for (int i = 0; i < S.length(); ++i)
- last[S.charAt(i) - 'a'] = i;
-
- int j = 0;
- int anchor = 0;
- List ans = new ArrayList<>();
- for (int i = 0; i < S.length(); ++i) {
- j = Math.max(j, last[S.charAt(i) - 'a']);
- if (i == j) {
- // it is (1+i-anchor)
- int length = i - anchor + 1;
- ans.add(length);
- anchor = i + 1;
- }
- }
- return ans;
- }
-
- public static void main(String[] args) {
- String S = "ababcbacadefegdehijhklij";
- PartitionLabel partition = new PartitionLabel();
- System.out.println(partition.partitionLabels(S));
-
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/Pattern132.java b/src/geeksforgeeks/Pattern132.java
deleted file mode 100644
index e2815e5..0000000
--- a/src/geeksforgeeks/Pattern132.java
+++ /dev/null
@@ -1,31 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Arrays;
-/*https://leetcode.com/problems/132-pattern/discuss/94089/Java-solutions-from-O(n3)-to-O(n)-for-%22132%22-pattern-(updated-with-one-pass-slution)*/
-public class Pattern132 {
-
-
- public static boolean find132pattern(int[] arr) {
- int[] temp = Arrays.copyOf(arr, arr.length);
-
- for (int i = 1; i < arr.length; i++) {
- temp[i] = Math.min(arr[i - 1], temp[i - 1]);
- }
- //{3, 3, 3, 1, 1, 1, 1, 1}
-
- for (int j = arr.length - 1, top = arr.length; j >= 0; j--) {
- if (arr[j] <= temp[j]) continue;
- while (top < arr.length && temp[top] <= temp[j]) top++;
- if (top < arr.length && arr[j] > temp[top]) return true;
- temp[--top] = arr[j];
- }
-
- return false;
- }
-
- public static void main(String[] args) {
- int[] arr = {3, 4, 1, 2, 9, 6, 7, 8};
-
- find132pattern(arr);
- }
-}
diff --git a/src/geeksforgeeks/ProductExceptSelf.java b/src/geeksforgeeks/ProductExceptSelf.java
deleted file mode 100644
index 6a0306e..0000000
--- a/src/geeksforgeeks/ProductExceptSelf.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Arrays;
-
-/**
- * https://leetcode.com/problems/product-of-array-except-self/
- */
-public class ProductExceptSelf {
- public static int[] productExceptSelf(int[] nums) {
- int n = nums.length;
- int[] res = new int[n];
- res[0] = 1;
- for (int i = 1; i < n; i++) {
- res[i] = res[i - 1] * nums[i - 1];
- }
- int right = 1;
- for (int i = n - 1; i >= 0; i--) {
- res[i] *= right;
- right *= nums[i];
- }
- return res;
- }
-
- public static void main(String[] args) {
- System.out.println(Arrays.toString(productExceptSelf(new int[]{1, 2, 3, 4, 5})));
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/RailwayPlatformProblem.java b/src/geeksforgeeks/RailwayPlatformProblem.java
deleted file mode 100644
index 60fadd4..0000000
--- a/src/geeksforgeeks/RailwayPlatformProblem.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Arrays;
-
-/**
- * https://www.geeksforgeeks.org/minimum-number-platforms-required-railwaybus-station/
- */
-public class RailwayPlatformProblem {
-
- static int findPlatform(int[] arrival, int[] departure, int n) {
- Arrays.sort(arrival);
- Arrays.sort(departure);
-
- int platNeeded = 1;
- int result = 1;
- int i = 1;
- int j = 0;
-
- while (i < n && j < n) {
- if (arrival[i] <= departure[j]) {
- platNeeded++;
- i++;
-
- if (platNeeded > result)
- result = platNeeded;
- } else {
- platNeeded--;
- j++;
- }
- }
- return result;
- }
-
- public static void main(String[] args) {
-
- int[] arr = {900, 940, 950, 1100, 1500, 1800};
- int[] dep = {910, 1200, 1120, 1130, 1900, 2000};
-
- int n = arr.length;
- System.out.println("Minimum Number of Platforms Required = " + findPlatform(arr, dep, n));
- }
-
-}
diff --git a/src/geeksforgeeks/RandomLinkedList.java b/src/geeksforgeeks/RandomLinkedList.java
deleted file mode 100644
index cd68a47..0000000
--- a/src/geeksforgeeks/RandomLinkedList.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package geeksforgeeks;
-
-class LLNode {
- public int val;
- public LLNode next;
- public LLNode random;
-
- public LLNode() {
- }
-
- public LLNode(int _val, LLNode _next, LLNode _random) {
- val = _val;
- next = _next;
- random = _random;
- }
-
- public String toString() {
- return "" + this.val;
- }
-};
-
-class RandomLinkedList {
- public LLNode copyRandomList(LLNode head) {
- if (head == null)
- return null;
- LLNode temp = head;
- while (temp != null) {
- LLNode LLNode = new LLNode(temp.val + 10, temp.next, null);
- temp.next = LLNode;
- temp = temp.next.next;
- }
- LLNode randomLLNode = head;
- while (randomLLNode != null) {
- randomLLNode.next.random = randomLLNode.random.next;
- randomLLNode = randomLLNode.next.next;
- }
- LLNode copyHead = head.next;
- LLNode tempHead = copyHead;
- while (head != null && tempHead != null) {
- head.next = head.next == null || head.next.next == null ? head.next : head.next.next;
- tempHead.next = tempHead.next == null || tempHead.next.next == null ? tempHead.next : tempHead.next.next;
- head = head.next;
- tempHead = tempHead.next;
- }
- return copyHead;
- }
-
- public static void main(String[] args) {
- LLNode head = new LLNode(1, null, null);
- head.next = new LLNode(2, null, null);
- head.next.next = new LLNode(3, null, null);
- head.next.next.next = new LLNode(4, null, null);
- head.random = head.next.next;
- head.next.random = head.next.next.next;
- head.next.next.random = head.next;
- head.next.next.next.random = head;
- RandomLinkedList solution = new RandomLinkedList();
- solution.copyRandomList(head);
- }
-}
diff --git a/src/geeksforgeeks/RemoveKDigits.java b/src/geeksforgeeks/RemoveKDigits.java
deleted file mode 100644
index e9b14c3..0000000
--- a/src/geeksforgeeks/RemoveKDigits.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Stack;
-
-/**
- * https://leetcode.com/problems/remove-k-digits/
- */
-
-public class RemoveKDigits {
- //1432219
- public static String removeKdigits(String num, int k) {
- int len = num.length();
-
- if (k == len)
- return "0";
-
- Stack stack = new Stack<>();
- int i = 0;
- while (i < num.length()) {
- while (k > 0 && !stack.isEmpty() && stack.peek() > num.charAt(i)) {
- stack.pop();
- k--;
- }
- stack.push(num.charAt(i));
- i++;
- }
-
- // corner case like "1111"
- while (k > 0) {
- stack.pop();
- k--;
- }
-
- StringBuilder sb = new StringBuilder();
- while (!stack.isEmpty())
- sb.append(stack.pop());
- sb.reverse();
-
- while (sb.length() > 1 && sb.charAt(0) == '0')
- sb.deleteCharAt(0);
- return sb.toString();
- }
-
- public static void main(String[] args) {
- System.out.println(removeKdigits("14232191", 3));
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/RestoreIPAddress.java b/src/geeksforgeeks/RestoreIPAddress.java
deleted file mode 100644
index 1ac6c71..0000000
--- a/src/geeksforgeeks/RestoreIPAddress.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package geeksforgeeks;
-
-import java.util.*;
-//unresolved
-class RestoreIPAddress {
-
- public List restoreIpAddresses(String s) {
- List result = new ArrayList<>();
- doRestore(result, "", s, 0);
- return result;
- }
-
- private void doRestore(List result, String path, String s, int k) {
- if (s.isEmpty() || k == 4) {
- if (s.isEmpty() && k == 4)
- result.add(path.substring(1));
- return;
- }
- for (int i = 1; i <= (s.charAt(0) == '0' ? 1 : 3) && i <= s.length(); i++) { // Avoid leading 0
- String part = s.substring(0, i);
- if (Integer.valueOf(part) <= 255) {
- System.out.println(path);
- doRestore(result, path + "." + part, s.substring(i), k + 1);
- }
- }
- }
-
- public static void main(String[] args) {
- RestoreIPAddress ip = new RestoreIPAddress();
- System.out.println(ip.restoreIpAddresses("25525511135").toString());
- }
-}
diff --git a/src/geeksforgeeks/RotateMatrixInPlace.java b/src/geeksforgeeks/RotateMatrixInPlace.java
deleted file mode 100644
index 950813b..0000000
--- a/src/geeksforgeeks/RotateMatrixInPlace.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package geeksforgeeks;
-
-/**
- * https://www.geeksforgeeks.org/inplace-rotate-square-matrix-by-90-degrees/
- */
-// looking for easy solution
-class RotateMatrixInPlace {
-
- /**
- * N/2 for time complexity o(n)
- *
- * get all the corners first and swap ( rotate 90 degree)
- *
- * @param N
- * @param mat
- */
- static void rotateMatrix(int N, int mat[][]) {
- // Consider all squares one by one
- for (int x = 0; x < N / 2; x++) {
- // Consider elements in group of 4 in
- // current square
- for (int y = x; y < N - x - 1; y++) {
- // store current cell in temp variable
- System.out.println("mat[" + x + "][" + y + "] = " + mat[x][y]);
- int temp = mat[x][y];
-
- // move values from right to top
- System.out.println("mat[" + y + "][" + (N - 1 - x) + "] = " + mat[y][N - 1 - x]);
- mat[x][y] = mat[y][N - 1 - x];
-
- // move values from bottom to right
- System.out.println("mat[" + (N - 1 - x) + "][" + (N - 1 - y) + "] = " + mat[N - 1 - x][N - 1 - y]);
- mat[y][N - 1 - x] = mat[N - 1 - x][N - 1 - y];
-
- // move values from left to bottom
- System.out.println("mat[" + (N - 1 - y) + "][" + (x) + "] = " + mat[N - 1 - y][x]);
- mat[N - 1 - x][N - 1 - y] = mat[N - 1 - y][x];
-
- // assign temp to left
- System.out.println("mat[" + (N - 1 - y) + "][" + (x) + "] = " + temp);
- mat[N - 1 - y][x] = temp;
- }
- }
- }
-
- static void displayMatrix(int N, int mat[][]) {
- for (int i = 0; i < N; i++) {
- for (int j = 0; j < N; j++)
- System.out.print(" " + mat[i][j]);
-
- System.out.print("\n");
- }
- System.out.print("\n");
- }
-
- public static void main(String[] args) {
- int N = 4;
-
- // Test Case 1
- int mat[][] = {{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}, {13, 14, 15, 16}};
-
- // int mat[][] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };
- // int mat[][] = { {1, 2}, {4, 5} };
-
- // displayMatrix(mat);
-
- rotateMatrix(N, mat);
-
- // Print rotated matrix
- displayMatrix(N, mat);
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/SearchAnElementInMatrix.java b/src/geeksforgeeks/SearchAnElementInMatrix.java
deleted file mode 100644
index 61bd8af..0000000
--- a/src/geeksforgeeks/SearchAnElementInMatrix.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package geeksforgeeks;
-/*https://www.youtube.com/watch?v=FOa55B9Ikfg
-* https://leetcode.com/problems/search-a-2d-matrix-ii/
-https://leetcode.com/problems/search-a-2d-matrix/*/
-
-
-public class SearchAnElementInMatrix {
-
- private static boolean searchII(int[][] mat, int n, int x) {
-
- int i = 0;
- int j = n - 1; // set indexes for top right element
-
- while (i < n && j >= 0) {
- if (mat[i][j] == x) {
- System.out.print("n Found at " + i + " " + j);
- return true;
- }
- if (mat[i][j] > x)
- j--;
- else // if mat[i][j] < x
- i++;
- }
-
- System.out.print("n Element not found");
- return false;
-
- }
-
- // why column : no.of.columns define the row correctly and rows wont help us to find the exact row
- public static boolean searchI(int[][] matrix, int target) {
- if (matrix == null || matrix.length == 0) {
- return false;
- }
- int start = 0;
- int rows = matrix.length;
- int cols = matrix[0].length;
- int end = rows * cols - 1;
- while (start <= end) {
- int mid = (start + end) / 2;
- if (matrix[mid / cols][mid % cols] == target) {
- return true;
- }
- if (matrix[mid / cols][mid % cols] < target) {
- start = mid + 1;
- } else {
- end = mid - 1;
- }
- }
- return false;
- }
-
- public static void main(String[] args) {
- int[][] mat = {{10, 20, 30, 40}, {15, 25, 35, 45}, {27, 29, 37, 48}, {32, 33, 39, 50}};
-
- int[][] matI = {{1, 3, 5, 7},
- {10, 11, 16, 20},
- {23, 30, 34, 50}};
-
- System.out.println(searchI(matI, 11));
- System.out.println(searchII(mat, 4, 33));
-
- }
-
-}
diff --git a/src/geeksforgeeks/SearchElementInSortedAndRotatedArray.java b/src/geeksforgeeks/SearchElementInSortedAndRotatedArray.java
deleted file mode 100644
index 64c5714..0000000
--- a/src/geeksforgeeks/SearchElementInSortedAndRotatedArray.java
+++ /dev/null
@@ -1,41 +0,0 @@
-package geeksforgeeks;
-
-/*https://leetcode.com/problems/search-in-rotated-sorted-array/*/
-public class SearchElementInSortedAndRotatedArray {
-
- public static void main(String[] args) {
- int[] arr = {4, 5, 6, 7, 0, 1, 2};
- SearchElementInSortedAndRotatedArray search = new SearchElementInSortedAndRotatedArray();
- System.out.println(search.searchInArray(arr, 1));
- }
-
- // 4, 5, 6, 7, 0, 1, 2
- int searchInArray(int arr[], int key) {
-
- int left = 0;
- int right = arr.length - 1;
-
- while (left < right) {
-
- int mid = (left + right) / 2;
- if (arr[mid] == key)
- return mid;
-
- if (arr[left] < arr[mid]) {
- if (key > arr[left] && key < arr[mid]) {
- right = mid - 1;
- } else {
- left = mid + 1;
- }
- } else {
- if (key > arr[mid] && key < arr[right]) {
- left = mid + 1;
- } else {
- right = mid - 1;
- }
- }
- }
- return -1;
- }
-
-}
diff --git a/src/geeksforgeeks/SerializeAndDeserialize.java b/src/geeksforgeeks/SerializeAndDeserialize.java
deleted file mode 100644
index 336a088..0000000
--- a/src/geeksforgeeks/SerializeAndDeserialize.java
+++ /dev/null
@@ -1,83 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.Queue;
-
-/*
- Serialize and Deserialize Binary Tree - LeetCode:
- https://leetcode.com/problems/serialize-and-deserialize-binary-tree/
-
- This code passes all Leetcode test cases as of April 26 2019
- Runtime: 12 ms, faster than 62.25% of Java online submissions for Serialize and Deserialize Binary Tree.
- Memory Usage: 39.4 MB, less than 71.37% of Java online submissions for Serialize and Deserialize Binary Tree.
-
- The video to explain this code is here: https://www.youtube.com/watch?v=suj1ro8TIVY
-*/
-
-public class SerializeAndDeserialize {
-
- private static final String NULL_SYMBOL = "X";
- private static final String DELIMITER = ",";
-
- public String serialize(TreeNode root) {
-
- if (root == null) {
- return NULL_SYMBOL + DELIMITER;
- }
-
- String leftSerialized = serialize(root.left);
- String rightSerialized = serialize(root.right);
-
- return root.val + DELIMITER + leftSerialized + rightSerialized;
- }
-
- public TreeNode deserialize(String data) {
- Queue nodesLeftToMaterialize = new LinkedList<>();
- nodesLeftToMaterialize.addAll(Arrays.asList(data.split(DELIMITER)));
- return deserializeHelper(nodesLeftToMaterialize);
- }
-
- public TreeNode deserializeHelper(Queue nodesLeftToMaterialize) {
-
- String valueForNode = nodesLeftToMaterialize.poll();
-
- if (valueForNode.equals(NULL_SYMBOL)) {
- return null;
- }
-
- TreeNode newNode = new TreeNode(Integer.valueOf(valueForNode));
- newNode.left = deserializeHelper(nodesLeftToMaterialize);
- newNode.right = deserializeHelper(nodesLeftToMaterialize);
-
- return newNode;
- }
-
- public static void main(String[] args) {
- TreeNode root = new TreeNode(1);
- root.left = new TreeNode(2);
- root.right = new TreeNode(3);
- root.left.right = new TreeNode(4);
- root.right.left = new TreeNode(5);
- root.right.right = new TreeNode(6);
- root.right.left.left = new TreeNode(7);
- root.right.left.right = new TreeNode(8);
- SerializeAndDeserialize sede = new SerializeAndDeserialize();
- String serialize = sede.serialize(root);
- System.out.println(serialize);
- TreeNode deserialze = sede.deserialize(serialize);
- sede.printTree(deserialze);
- }
-
- public void printTree(TreeNode node) {
- if (node == null) {
- System.out.print("X,");
- return;
- }
- System.out.print(node.val + ",");
- printTree(node.left);
- printTree(node.right);
- }
-
-}
-
diff --git a/src/geeksforgeeks/SimilarExperssions.java b/src/geeksforgeeks/SimilarExperssions.java
deleted file mode 100644
index 37456b9..0000000
--- a/src/geeksforgeeks/SimilarExperssions.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package geeksforgeeks;
-
-/**
- * https://www.geeksforgeeks.org/check-two-expressions-brackets/
- *
- */
-//unresolved
-public class SimilarExperssions {
-
- public static void main(String[] args) {
-
- System.out.println('+' * '-');
-
- String query = "-(a+b+c)";
- String response = "-a-b-c";
-
- checkExpression(query.toCharArray(), response.toCharArray());
- }
-
- private static void checkExpression(char[] query, char[] response) {
-
- char symbol = 0;
- int startIndex = 0;
- int endIndex = 0;
- for (int i = 0; i < query.length; i++) {
- if (query[i] == '(') {
- symbol = query[i - 1];
- startIndex = i + 1;
- } else if (query[i] == ')') {
- endIndex = i - 1;
- solve(symbol, startIndex, endIndex, query);
-
- }
- }
- }
-
- private static void solve(char symbol, int startIndex, int endIndex, char[] query) {
-
- for (int i = startIndex; i <= endIndex; i++) {
- char temp = 0;
- if (query[startIndex] == '-') {
- temp = '-' * '+';
- query[i] = temp;
- } else if (symbol == '+') {
- temp = '-';
- query[i] = temp;
- } else if (Character.isLetter(query[startIndex])) {
- if (startIndex == i) {
- query[startIndex - 1] = temp;
- }
- System.out.print(query[startIndex]);
- }
- System.out.print(temp);
- }
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/SlidingWindow.java b/src/geeksforgeeks/SlidingWindow.java
deleted file mode 100644
index 0f54c68..0000000
--- a/src/geeksforgeeks/SlidingWindow.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Deque;
-import java.util.LinkedList;
-
-public class SlidingWindow {
-
- public static void main(String[] args) {
- int arr[] = {8, 5, 10, 7, 9, 4, 15, 12, 90, 13};
- int k = 3;
- printMax(arr, arr.length, k);
- }
-
- private static void printMax(int[] arr, int length, int k) {
- Deque deque = new LinkedList<>();
- int i = 0;
- for (; i < k; i++) {
- while (!deque.isEmpty() && arr[i] >= arr[deque.peekLast()])
- deque.removeLast();
- deque.addLast(i);
- }
- for (; i < length; i++) {
- System.out.println(arr[deque.peekFirst()]);
-
- while (!deque.isEmpty() && deque.peekFirst() <= i - k)
- deque.removeFirst();
-
- while (!deque.isEmpty() && arr[i] >= arr[deque.peekLast()])
- deque.removeLast();
-
- deque.addLast(i);
- }
- System.out.println(arr[deque.peekFirst()]);
- }
-
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/SnakeAndLadder.java b/src/geeksforgeeks/SnakeAndLadder.java
deleted file mode 100644
index cc10da3..0000000
--- a/src/geeksforgeeks/SnakeAndLadder.java
+++ /dev/null
@@ -1,72 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Queue;
-import java.util.LinkedList;
-
-/**
- * https://leetcode.com/problems/snakes-and-ladders/
- */
-public class SnakeAndLadder {
-
- static class QEntry {
- int vertex;
- int noOfMoves;
- }
-
- static int getMinDiceThrows(int board[], int n) {
- Queue queue = new LinkedList<>();
- QEntry qEntry = new QEntry();
- qEntry.vertex = 0;
- qEntry.noOfMoves = 0;
-
- board[0] = -21;
- queue.add(qEntry);
-
- while (!queue.isEmpty()) {
- qEntry = queue.remove();
- int v = qEntry.vertex;
-
- System.out.println(v);
-
- if (v == n - 1)
- break;
-
- for (int j = v + 1; j <= (v + 6) && j < n; j++) {
- if (board[j] != -21) {
- QEntry entry = new QEntry();
- entry.noOfMoves = (qEntry.noOfMoves + 1);
-
- if (board[j] != -1)
- entry.vertex = board[j];
- else
- entry.vertex = j;
- queue.add(entry);
- board[j] = -21;
- }
- }
- }
- return qEntry.noOfMoves;
- }
-
- public static void main(String[] args) {
-
- int N = 30;
- int moves[] = new int[N];
- for (int i = 0; i < N; i++)
- moves[i] = -1;
-
- // Ladders
- moves[2] = 21;
- moves[4] = 7;
- moves[10] = 25;
- moves[19] = 28;
-
- // Snakes
- moves[3] = 1;
- moves[23] = 8;
- moves[16] = 3;
- moves[18] = 6;
-
- System.out.println("Min Dice throws required is " + getMinDiceThrows(moves, N));
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/SpiralMatrix.java b/src/geeksforgeeks/SpiralMatrix.java
deleted file mode 100644
index c6d83cb..0000000
--- a/src/geeksforgeeks/SpiralMatrix.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package geeksforgeeks;
-
-class SpiralMatrix {
-
- static void spiralPrint(int rowEnd, int colEnd, int a[][]) {
- int rowStart = 0;
- int colStart = 0;
-
- while (rowStart < colEnd && colStart < rowEnd) {
- // Print the first row from the remaining rowEnd
- for (int i = colStart; i < rowEnd; ++i) {
- System.out.print(a[rowStart][i] + " ");
- }
- rowStart++;
-
- // Print the last column from the remaining colEnd
- for (int i = rowStart; i < colEnd; ++i) {
- System.out.print(a[i][rowEnd - 1] + " ");
- }
- rowEnd--;
-
- // Print the last row from the remaining rowEnd */
- if (rowStart < colEnd) {
- for (int i = rowEnd - 1; i >= colStart; --i) {
- System.out.print(a[colEnd - 1][i] + " ");
- }
- colEnd--;
- }
-
- // Print the first column from the remaining colEnd */
- if (colStart < rowEnd) {
- for (int i = colEnd - 1; i >= rowStart; --i) {
- System.out.print(a[i][colStart] + " ");
- }
- colStart++;
- }
- }
- }
-
- public static void main(String[] args) {
- int R = 4;
- int C = 4;
- int a[][] = {{1, 2, 3, 4},
- {5, 6, 7, 8},
- {9, 10, 11, 12},
- {13, 14, 15, 16}};
- spiralPrint(R, C, a);
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/SpiralMatrixII.java b/src/geeksforgeeks/SpiralMatrixII.java
deleted file mode 100644
index 7cb1b22..0000000
--- a/src/geeksforgeeks/SpiralMatrixII.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Arrays;
-
-public class SpiralMatrixII {
-
- public static int[][] generateMatrix(int n) {
- // Declaration
- int[][] matrix = new int[n][n];
-
- // Edge Case
- if (n == 0) {
- return matrix;
- }
-
-
- // Normal Case
- int rowStart = 0;
- int rowEnd = n - 1;
- int colStart = 0;
- int colEnd = n - 1;
- int num = 1; // change
-
- while (rowStart <= rowEnd && colStart <= colEnd) {
- for (int i = colStart; i <= colEnd; i++) {
- matrix[rowStart][i] = num++; // change
- }
- rowStart++;
-
- for (int i = rowStart; i <= rowEnd; i++) {
- matrix[i][colEnd] = num++; // change
- }
- colEnd--;
-
- for (int i = colEnd; i >= colStart; i--) {
- if (rowStart <= rowEnd)
- matrix[rowEnd][i] = num++; // change
- }
- rowEnd--;
-
- for (int i = rowEnd; i >= rowStart; i--) {
- if (colStart <= colEnd)
- matrix[i][colStart] = num++; // change
- }
- colStart++;
-
- System.out.println(Arrays.deepToString(matrix));
- }
-
- return matrix;
- }
-
- public static void main(String[] args) {
- generateMatrix(4);
- }
-}
diff --git a/src/geeksforgeeks/SplitLinkedList.java b/src/geeksforgeeks/SplitLinkedList.java
deleted file mode 100644
index fb3e4d5..0000000
--- a/src/geeksforgeeks/SplitLinkedList.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package geeksforgeeks;
-
-//https://leetcode.com/problems/split-linked-list-in-parts/
-class SplitLinkedList {
- public ListNode[] splitListToParts(ListNode root, int k) {
- if (root == null) return null;
- if (k == 0) return null;
-
- if (k == 1) {
- ListNode[] node = new ListNode[1];
- node[0] = root;
- return node;
- }
-
-
- ListNode[] node = new ListNode[k];
- int length = getRootLength(root);
-
- if (k > length) {
- ListNode temp = root;
- int index = 0;
-
- while (temp != null) {
- ListNode result = temp;
- temp = temp.next;
- result.next = null;
- node[index] = result;
- index++;
- }
-
- for (; index < k; index++) {
- node[index] = null;
- }
- return node;
- }
-
- int remainder = length % k;
- int quo = length / k;
-
- for (int i = 0; i < k; i++) {
- int value = remainder > 0 ? quo + 1 : quo;
- remainder--;
- ListNode head = root;
- ListNode prev = null;
- for (int j = 0; j < value && root != null; j++) {
- if (j == value - 1) {
- prev = root;
- prev.next = null;
- }
- root = root.next;
- }
- node[i] = head;
- }
-
- return node;
- }
-
- public int getRootLength(ListNode root) {
- ListNode temp = root;
- int count = 0;
- while (temp != null) {
- count++;
- temp = temp.next;
- }
- return count;
- }
-
- public static void main(String[] args) {
- ListNode root = new ListNode(1);
- root.next = new ListNode(2);
- root.next.next = new ListNode(3);
- root.next.next.next = new ListNode(4);
- root.next.next.next.next = new ListNode(5);
- root.next.next.next.next.next = new ListNode(6);
- root.next.next.next.next.next.next = new ListNode(7);
- root.next.next.next.next.next.next.next = new ListNode(8);
- root.next.next.next.next.next.next.next.next = new ListNode(9);
- root.next.next.next.next.next.next.next.next.next = new ListNode(10);
- new SplitLinkedList().splitListToParts(root, 3);
- }
-}
diff --git a/src/geeksforgeeks/StockBuySellManyTimes.java b/src/geeksforgeeks/StockBuySellManyTimes.java
deleted file mode 100644
index c4a4587..0000000
--- a/src/geeksforgeeks/StockBuySellManyTimes.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package geeksforgeeks;
-
-import java.util.ArrayList;
-import java.util.List;
-
-class Interval {
- int buy, sell;
-}
-
-/**
- * https://www.geeksforgeeks.org/stock-buy-sell/
- */
-// unresolved
-class StockBuySellManyTimes {
-
- //200, 180, 260, 310, 40, 535, 695
- void stockBuySell(int price[], int n) {
- // Prices must be given for at least two days
- if (n == 1)
- return;
-
- int count = 0;
-
- List result = new ArrayList<>();
-
- int i = 0;
- while (i < n - 1) {
- // Find Local Minima. Note that the limit is (n-2) as we are
- // comparing present element to the next element.
- while ((i < n - 1) && (price[i + 1] <= price[i]))
- i++;
-
- // If we reached the end, break as no further solution possible
- if (i == n - 1)
- break;
-
- Interval e = new Interval();
- e.buy = i++;
- // Store the index of minima
-
- // Find Local Maxima. Note that the limit is (n-1) as we are
- // comparing to previous element
- while ((i < n) && (price[i] >= price[i - 1]))
- i++;
-
- // Store the index of maxima
- e.sell = i - 1;
- result.add(e);
-
- // Increment number of buy/sell
- count++;
- }
-
- if (count == 0)
- System.out.println("There is no day when buying the stock " + "will make profit");
- else
- for (int j = 0; j < count; j++)
- System.out.println("Buy on day: " + result.get(j).buy + " " + "Sell on day : " + result.get(j).sell);
-
- return;
- }
-
- public static void main(String args[]) {
- StockBuySellManyTimes stock = new StockBuySellManyTimes();
-
- int price[] = {200, 180, 260, 310, 40, 535, 695};
- int n = price.length;
-
- stock.stockBuySell(price, n);
- }
-}
diff --git a/src/geeksforgeeks/SumOfThreeElements.java b/src/geeksforgeeks/SumOfThreeElements.java
deleted file mode 100644
index 108825a..0000000
--- a/src/geeksforgeeks/SumOfThreeElements.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package geeksforgeeks;
-
-import java.util.Arrays;
-
-public class SumOfThreeElements {
-
- public static void main(String[] args) {
- int arr[] = {1, 4, 45, 6, 10, 8};
- int sum = 22;
- SumOfThreeElements ste = new SumOfThreeElements();
- ste.findTriplets(arr, sum);
- }
-
- private boolean findTriplets(int[] arr, int sum) {
-
- int arrSize = arr.length;
- Arrays.sort(arr);
-
- for (int i = 0; i < arrSize; i++) {
-
- int left = i + 1;
- int right = arrSize - 1;
-
- while (left < right) {
- int result = arr[i] + arr[left] + arr[right];
- if (result == sum) {
- System.out.println("triplet found" + i + "+" + left + "+" + right);
- break;
- } else if (result < sum) {
- left++;
- } else {
- right--;
- }
- }
- }
-
- return false;
- }
-}
diff --git a/src/geeksforgeeks/SwapRecoverBST.java b/src/geeksforgeeks/SwapRecoverBST.java
deleted file mode 100644
index 4de4707..0000000
--- a/src/geeksforgeeks/SwapRecoverBST.java
+++ /dev/null
@@ -1,44 +0,0 @@
-package geeksforgeeks;
-
-public class SwapRecoverBST {
-
- TreeNode firstElement = null;
- TreeNode secondElement = null;
- // The reason for this initialization is to avoid null pointer exception in the first comparison when prevElement has not been initialized
- TreeNode prevElement = new TreeNode(Integer.MIN_VALUE);
-
- public void recoverTree(TreeNode root) {
-
- // In order traversal to find the two elements
- traverse(root);
-
- // Swap the values of the two nodes
- int temp = firstElement.val;
- firstElement.val = secondElement.val;
- secondElement.val = temp;
- }
-
- private void traverse(TreeNode root) {
-
- if (root == null)
- return;
-
- traverse(root.left);
-
- // Start of "do some business",
- // If first element has not been found, assign it to prevElement (refer to 6 in the example above)
- if (firstElement == null && prevElement.val >= root.val) {
- firstElement = prevElement;
- }
-
- // If first element is found, assign the second element to the root (refer to 2 in the example above)
- if (firstElement != null && prevElement.val >= root.val) {
- secondElement = root;
- }
- prevElement = root;
-
- // End of "do some business"
-
- traverse(root.right);
- }
-}
\ No newline at end of file
diff --git a/src/geeksforgeeks/TaskLeastInterval.java b/src/geeksforgeeks/TaskLeastInterval.java
deleted file mode 100644
index 107fbad..0000000
--- a/src/geeksforgeeks/TaskLeastInterval.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package geeksforgeeks;
-
-import java.util.*;
-
-/*https://leetcode.com/problems/task-scheduler/*/
-// unresolved
-public class TaskLeastInterval {
-
- public static int leastInterval(char[] tasks, int n) {
- Map map = new HashMap<>();
- for (int i = 0; i < tasks.length; i++) {
- map.put(tasks[i], map.getOrDefault(tasks[i], 0) + 1);
- }
- PriorityQueue> queue = new PriorityQueue<>(
- (a, b) -> Integer.compare(b.getValue(), a.getValue()));
-
- queue.addAll(map.entrySet());
-
- int count = 0;
- while (!queue.isEmpty()) {
- int k = n + 1;
- List tempList = new ArrayList<>();
- while (k > 0 && !queue.isEmpty()) {
- Map.Entry top = queue.poll();
- top.setValue(top.getValue() - 1);
- tempList.add(top);
- k--;
- count++;
- }
-
- for (Map.Entry e : tempList) {
- if (e.getValue() > 0) queue.add(e); // add valid tasks
- }
-
- if (queue.isEmpty()) break;
- count = count + k; // if k > 0, then it means we need to be idle
- }
- return count;
- }
-
- public static void main(String[] args) {
- char[] arr = "AAAAAABCDEFG".toCharArray();
- leastInterval(arr, 2);
- }
-}
diff --git a/src/geeksforgeeks/UniquePath.java b/src/geeksforgeeks/UniquePath.java
deleted file mode 100644
index c022223..0000000
--- a/src/geeksforgeeks/UniquePath.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package geeksforgeeks;
-
-/*https://leetcode.com/problems/unique-paths-ii/
- https://leetcode.com/problems/unique-paths/*/
-public class UniquePath {
-
- public static void main(String[] args) {
- System.out.println(uniquePathI(3, 2));
-
- int[][] matrix = {{0, 0, 0},
- {0, 1, 0},
- {0, 0, 0}};
-
- System.out.println(uniquePathII(matrix));
-
- }
-
- private static int uniquePathI(int row, int col) {
- int[][] dp = new int[row][col];
-
- for (int i = 0; i < col; i++) {
- dp[0][i] = 1;
- }
-
- for (int j = 0; j < row; j++) {
- dp[j][0] = 1;
- }
-
- for (int i = 1; i < row; i++) {
- for (int j = 1; j < col; j++) {
- dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
- }
- }
- return dp[row - 1][col - 1];
- }
-
-
- private static int uniquePathII(int[][] mat) {
- int[][] dp = new int[mat.length][mat[0].length];
- for (int i = 0; i < mat[0].length; i++) {
- if (mat[0][i] != 1) {
- dp[0][i] = 1;
- }
- }
-
- for (int i = 0; i < mat.length; i++) {
- if (mat[i][0] != 1) {
- dp[i][0] = 1;
- }
- }
-
- for (int i = 1; i < mat.length; i++) {
- for (int j = 1; j < mat[0].length; j++) {
- if (mat[i][j] == 1) {
- dp[i][j] = 0;
- } else {
- dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
- }
-
- }
- }
- return dp[mat.length - 1][mat[0].length - 1];
- }
-}
diff --git a/src/geeksforgeeks/VulgarDecimal.java b/src/geeksforgeeks/VulgarDecimal.java
deleted file mode 100644
index 973665e..0000000
--- a/src/geeksforgeeks/VulgarDecimal.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package geeksforgeeks;
-
-/*https://leetcode.com/problems/fraction-to-recurring-decimal/*/
-
-import java.util.*;
-
-public class VulgarDecimal {
-
- public static String fractionToDecimal(long num, long den) {
- if (num == 0) {
- return "0";
- }
- StringBuilder result = new StringBuilder();
-
- result.append(((num > 0) ^ (den > 0)) ? "-" : "");
- result.append(num / den);
- num %= den;
- if (num == 0) {
- return result.toString();
- }
-
- result.append(".");
- HashMap map = new HashMap<>();
- map.put(num, result.length());
- while (num != 0) {
- num *= 10;
- result.append(num / den);
- num %= den;
- if (map.containsKey(num)) {
- int index = map.get(num);
- result.insert(index, "(");
- result.append(")");
- break;
- } else {
- map.put(num, result.length());
- }
- }
- return result.toString();
- }
-
-
- /**
- * boolean doTestsPass()
- * Returns true if all tests pass. Otherwise false
- *
- * Consider adding more tests.
- */
- public static boolean doTestsPass() {
- boolean testsPassed = true;
-
- // testsPassed &= fractionToDecimal(1l, 2l).equals("0.5");
- //testsPassed &= fractionToDecimal(1l, 3l).equals("0.(3)");
- //testsPassed &= fractionToDecimal(1l, 30l).equals("0.0(3)");
- //testsPassed &= fractionToDecimal(1l, 75l).equals("0.01(3)");
- //testsPassed &= fractionToDecimal(4l, 7l).equals("0.(571428)");
- testsPassed &= fractionToDecimal(1l, 56l).equals("0.017(857142)");
-
- if (testsPassed) {
- System.out.println("Tests passes");
- } else {
- System.out.println("Tests failed");
- }
- return testsPassed;
- }
-
- public static void main(String[] args) {
- doTestsPass();
- }
-}
diff --git a/src/geeksforgeeks/WaterTrapping.java b/src/geeksforgeeks/WaterTrapping.java
deleted file mode 100644
index e76f6eb..0000000
--- a/src/geeksforgeeks/WaterTrapping.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package geeksforgeeks;
-
-class WaterTrapping {
-
- static int findWater(int arr[], int n) {
- int result = 0;
- int leftMax = 0;
- int rightMax = 0;
- int low = 0;
- int high = n - 1;
-
- while (low < high) {
- if (arr[low] < arr[high]) {
- if (arr[low] > leftMax) {
- leftMax = arr[low];
- } else {
- result += leftMax - arr[low];
- }
- low++;
- } else {
- if (arr[high] > rightMax) {
- rightMax = arr[high];
- } else {
- result += rightMax - arr[high];
- }
- high--;
- }
- }
- return result;
- }
-
- public static void main(String[] args) {
- int arr[] = {0, 1, 0, 2, 1, 0, 1, 3, 2, 1};
- int n = arr.length;
- System.out.println("Maximum water that " + "can be accumulated is " + findWater(arr, n));
- }
-}
\ No newline at end of file
diff --git a/src/main/java/RandomProblemGenerator.java b/src/main/java/RandomProblemGenerator.java
new file mode 100644
index 0000000..69074d5
--- /dev/null
+++ b/src/main/java/RandomProblemGenerator.java
@@ -0,0 +1,35 @@
+import java.io.BufferedReader;
+import java.io.File;
+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.List;
+import java.util.Random;
+import java.util.stream.Collectors;
+
+public class RandomProblemGenerator {
+ public static void main(String[] args) throws IOException {
+ List filesInFolder = Files.walk(Paths.get("src/main/java"))
+ .filter(Files::isRegularFile)
+ .map(Path::toFile)
+ .filter(file -> !(file.getPath().contains("lld") ||
+ file.getPath().contains("java8") ||
+ file.getPath().contains("reflections") ||
+ file.getPath().contains("multithreading") ||
+ file.getPath().contains("internals")))
+ .filter(file -> file.getName().contains(".java"))
+ .collect(Collectors.toList());
+
+ int rand= (new Random().nextInt(filesInFolder.size()));
+ System.out.println(rand+" "+filesInFolder.get(rand).getName());
+ try (BufferedReader reader =
+ new BufferedReader(new FileReader(filesInFolder.get(rand)))){
+ reader.lines().filter(e->e.contains("http") || e.contains("https")).forEach(System.out::println);
+ }
+
+ System.out.println("Total files: "+filesInFolder.size());
+ }
+
+}
diff --git a/src/main/java/SQL/AlterTableWithMonthName.sql b/src/main/java/SQL/AlterTableWithMonthName.sql
new file mode 100644
index 0000000..8541ba7
--- /dev/null
+++ b/src/main/java/SQL/AlterTableWithMonthName.sql
@@ -0,0 +1,35 @@
+
+--when you give query like this
+--SELECT id,
+--CASE WHEN month = "Jan" THEN revenue END as "Jan_Revenue",
+--CASE WHEN month = "Feb" THEN revenue END AS "Feb_Revenue"
+--FROM Department;
+--the output will be
+--+----+-------------+-------------+
+--| id | Jan_Revenue | Feb_Revenue |
+--+----+-------------+-------------+
+--| 1 | NULL | 7000 |
+--| 1 | 8000 | NULL |
+--| 1 | NULL | NULL |
+--| 2 | 9000 | NULL |
+--| 3 | NULL | 10000 |
+--+----+-------------+-------------+
+--To get one row for each id we need to aggregate by id using GROUP BY.
+--But since we have multiple rows with the same id but different values (e.g. for id=1 we have Jan_Revenues:
+-- NULL, 8000 and NULL. When we merge these 3 together what value should be chosen?
+--This is why we need either SUM (NULL+8000+NULL) or MAX, in both cases 8000 will be used
+
+SELECT id,
+MAX(CASE WHEN month='Jan' then revenue else null end) Jan_Revenue,
+MAX(CASE WHEN month='Feb' then revenue else null end) Feb_Revenue,
+MAX(CASE WHEN month='Mar' then revenue else null end) Mar_Revenue,
+MAX(CASE WHEN month='Apr' then revenue else null end) Apr_Revenue,
+MAX(CASE WHEN month='May' then revenue else null end) May_Revenue,
+MAX(CASE WHEN month='Jun' then revenue else null end) Jun_Revenue,
+MAX(CASE WHEN month='Jul' then revenue else null end) Jul_Revenue,
+MAX(CASE WHEN month='Aug' then revenue else null end) Aug_Revenue,
+MAX(CASE WHEN month='Sep' then revenue else null end) Sep_Revenue,
+MAX(CASE WHEN month='Oct' then revenue else null end) Oct_Revenue,
+MAX(CASE WHEN month='Nov' then revenue else null end) Nov_Revenue,
+MAX(CASE WHEN month='Dec' then revenue else null end) Dec_Revenue
+FROM Department GROUP BY id
\ No newline at end of file
diff --git a/src/main/java/SQL/ClassHavingMoreStudents.sql b/src/main/java/SQL/ClassHavingMoreStudents.sql
new file mode 100644
index 0000000..86808a4
--- /dev/null
+++ b/src/main/java/SQL/ClassHavingMoreStudents.sql
@@ -0,0 +1,29 @@
+--+---------+------------+
+--| student | class |
+--+---------+------------+
+--| A | Math |
+--| B | English |
+--| C | Math |
+--| D | Biology |
+--| E | Math |
+--| F | Computer |
+--| G | Math |
+--| H | Math |
+--| I | Math |
+--+---------+------------+
+
+--output:
+--
+--+---------+
+--| class |
+--+---------+
+--| Math |
+--+---------+
+
+
+SELECT
+ class
+FROM
+ courses
+GROUP BY class
+HAVING COUNT(DISTINCT student) >= 5
\ No newline at end of file
diff --git a/src/main/java/SQL/CustomersNerverOrders.sql b/src/main/java/SQL/CustomersNerverOrders.sql
new file mode 100644
index 0000000..1bbd733
--- /dev/null
+++ b/src/main/java/SQL/CustomersNerverOrders.sql
@@ -0,0 +1,24 @@
+--Suppose that a website contains two tables, the Customers table and the Orders table. Write a SQL query to find all customers who never order anything.
+--
+--Table: Customers.
+--
+--+----+-------+
+--| Id | Name |
+--+----+-------+
+--| 1 | Joe |
+--| 2 | Henry |
+--| 3 | Sam |
+--| 4 | Max |
+--+----+-------+
+--Table: Orders.
+--
+--+----+------------+
+--| Id | CustomerId |
+--+----+------------+
+--| 1 | 3 |
+--| 2 | 1 |
+--+----+------------+
+
+
+select cu.Name as Customers from Customers cu left join Orders od on cu.Id=od.CustomerId
+where od.CustomerId is null
\ No newline at end of file
diff --git a/src/main/java/SQL/DeleteDuplicate.sql b/src/main/java/SQL/DeleteDuplicate.sql
new file mode 100644
index 0000000..06ea0f8
--- /dev/null
+++ b/src/main/java/SQL/DeleteDuplicate.sql
@@ -0,0 +1,5 @@
+
+
+-- the below command will do cross product and generate all combinations of rows
+-- we are selecting a row with same Email and Greater Id
+DELETE p1 from Person p1, Person p2 where p1.Email=p2.Email and p1.Id>p2.Id
\ No newline at end of file
diff --git a/src/main/java/SQL/DepartmentHighestSalary.sql b/src/main/java/SQL/DepartmentHighestSalary.sql
new file mode 100644
index 0000000..2589613
--- /dev/null
+++ b/src/main/java/SQL/DepartmentHighestSalary.sql
@@ -0,0 +1,50 @@
+
+--+----+-------+--------+--------------+
+--| Id | Name | Salary | DepartmentId |
+--+----+-------+--------+--------------+
+--| 1 | Joe | 70000 | 1 |
+--| 2 | Jim | 90000 | 1 |
+--| 3 | Henry | 80000 | 2 |
+--| 4 | Sam | 60000 | 2 |
+--| 5 | Max | 90000 | 1 |
+--+----+-------+--------+--------------+
+
+--+----+----------+
+--| Id | Name |
+--+----+----------+
+--| 1 | IT |
+--| 2 | Sales |
+--+----+----------+
+
+--OUTPUT
+--+------------+----------+--------+
+--| Department | Employee | Salary |
+--+------------+----------+--------+
+--| IT | Max | 90000 |
+--| IT | Jim | 90000 |
+--| Sales | Henry | 80000 |
+--+------------+----------+--------+
+
+--this inner query will give single top salaries for each dept, however if there are multiple people who gets the same salary? we do one more join
+-- SELECT d.Id
+-- , MAX(d.Name) AS Name
+-- , MAX(e.Salary) AS Salary
+-- FROM Department d
+-- JOIN Employee e
+-- ON e.DepartmentId = d.Id
+-- GROUP BY d.Id
+
+SELECT d1.Name as Department
+ , e1.Name as Employee
+ , e1.Salary
+FROM (
+ SELECT d.Id
+ , MAX(d.Name) AS Name
+ , MAX(e.Salary) AS Salary
+ FROM Department d
+ JOIN Employee e
+ ON e.DepartmentId = d.Id
+ GROUP BY d.Id
+) d1
+JOIN Employee e1
+ON d1.Id = e1.DepartmentId AND e1.Salary = d1.Salary
\ No newline at end of file
diff --git a/src/main/java/SQL/DuplicateEmail.sql b/src/main/java/SQL/DuplicateEmail.sql
new file mode 100644
index 0000000..b635a55
--- /dev/null
+++ b/src/main/java/SQL/DuplicateEmail.sql
@@ -0,0 +1,20 @@
+--Write a SQL query to find all duplicate emails in a table named Person.
+--+----+---------+
+--| Id | Email |
+--+----+---------+
+--| 1 | a@b.com |
+--| 2 | c@d.com |
+--| 3 | a@b.com |
+--+----+---------+
+
+select distinct(t1.Email) as Email
+from Person t1
+where 1<(
+ select count(t2.Email)
+ from Person t2 where t1.Email=t2.Email)
+
+ -- Inner Join concept
+select distinct p1.Email
+from Person p1
+inner join Person p2 on p1.Email=P2.Email
+where p1.Id <> p2.Id
\ No newline at end of file
diff --git a/src/main/java/SQL/EmployeeEarningHigherThanManagers.sql b/src/main/java/SQL/EmployeeEarningHigherThanManagers.sql
new file mode 100644
index 0000000..f912bae
--- /dev/null
+++ b/src/main/java/SQL/EmployeeEarningHigherThanManagers.sql
@@ -0,0 +1,3 @@
+
+
+select tb1.Name as Employee from Employee tb1 inner join Employee tb2 on tb1.ManagerId=tb2.Id where tb1.Salary>tb2.Salary
diff --git a/src/main/java/SQL/ExchangeSeats.sql b/src/main/java/SQL/ExchangeSeats.sql
new file mode 100644
index 0000000..3e425ec
--- /dev/null
+++ b/src/main/java/SQL/ExchangeSeats.sql
@@ -0,0 +1,27 @@
+--Mary is a teacher in a middle school and she has a table seat storing students' names and their corresponding seat ids.
+--
+--The column id is continuous increment.
+--
+--+---------+---------+
+--| id | student |
+--+---------+---------+
+--| 1 | Abbot |
+--| 2 | Doris |
+--| 3 | Emerson |
+--| 4 | Green |
+--| 5 | Jeames |
+--+---------+---------+
+
+--For students with odd id, the new id is (id+1) after switch unless it is the last seat. And for students with even id, the new id is (id-1).
+--In order to know how many seats in total, we can use a subquery:
+--gotcha is when we do id+1 we shouldn't exceed the row number so when id==count we leave as is
+
+select (case
+ when MOD(id,2)!=0 && id!=counts then id+1
+ when MOD(id,2)!=0 && id=counts then id
+ else id-1
+ end) as id, student
+ from
+ seat,
+ (select count(*) as counts from seat) as seat_counts
+ order by id asc
\ No newline at end of file
diff --git a/src/main/java/SQL/FirstLoginDate.sql b/src/main/java/SQL/FirstLoginDate.sql
new file mode 100644
index 0000000..9d78cce
--- /dev/null
+++ b/src/main/java/SQL/FirstLoginDate.sql
@@ -0,0 +1,34 @@
+
+--Write an SQL query that reports the first login date for each player.
+--
+--The query result format is in the following example:
+--
+--Activity table:
+--+-----------+-----------+------------+--------------+
+--| player_id | device_id | event_date | games_played |
+--+-----------+-----------+------------+--------------+
+--| 1 | 2 | 2016-03-01 | 5 |
+--| 1 | 2 | 2016-05-02 | 6 |
+--| 2 | 3 | 2017-06-25 | 1 |
+--| 3 | 1 | 2016-03-02 | 0 |
+--| 3 | 4 | 2018-07-03 | 5 |
+--+-----------+-----------+------------+--------------+
+--
+--Result table:
+--+-----------+-------------+
+--| player_id | first_login |
+--+-----------+-------------+
+--| 1 | 2016-03-01 |
+--| 2 | 2017-06-25 |
+--| 3 | 2016-03-02 |
+--+-----------+-------------+
+
+
+select player_id, min(event_date) as first_login from Activity group by player_id
+
+
+--the following query is to try and get first loggedin deviceId
+
+SELECT player_id, device_id FROM Activity
+WHERE (player_id, event_date) IN
+(SELECT player_id, MIN(event_date) first_date FROM Activity GROUP BY player_id)
\ No newline at end of file
diff --git a/src/main/java/SQL/ManagerHaving5OrMoreReport.sql b/src/main/java/SQL/ManagerHaving5OrMoreReport.sql
new file mode 100644
index 0000000..988a525
--- /dev/null
+++ b/src/main/java/SQL/ManagerHaving5OrMoreReport.sql
@@ -0,0 +1,22 @@
+
+--+------+----------+-----------+----------+
+--|Id |Name |Department |ManagerId |
+--+------+----------+-----------+----------+
+--|101 |John |A |null |
+--|102 |Dan |A |101 |
+--|103 |James |A |101 |
+--|104 |Amy |A |101 |
+--|105 |Anne |A |101 |
+--|106 |Ron |B |101 |
+--+------+----------+-----------+----------+
+--
+--Given the Employee table, write a SQL query that finds out managers with at least 5 direct report. For the above table, your SQL query should return:
+--
+--+-------+
+--| Name |
+--+-------+
+--| John |
+--+-------+
+
+
+select (e2.Name) from Employee e1 inner join Employee e2 on e1.ManagerId=e2.Id group by e1.managerid having count(*) >= 5
diff --git a/src/main/java/SQL/NthHighestSalary.sql b/src/main/java/SQL/NthHighestSalary.sql
new file mode 100644
index 0000000..812e4cc
--- /dev/null
+++ b/src/main/java/SQL/NthHighestSalary.sql
@@ -0,0 +1,10 @@
+--N is passed as parameter
+
+CREATE FUNCTION getNthHighestSalary(N INT) RETURNS INT
+BEGIN
+DECLARE M INT; #note variable declaration
+SET M=N-1;
+ RETURN (
+ select distinct(salary) from Employee order by Salary desc limit M,1
+ );
+END
\ No newline at end of file
diff --git a/src/main/java/SQL/RisingTemperature.sql b/src/main/java/SQL/RisingTemperature.sql
new file mode 100644
index 0000000..6e0492d
--- /dev/null
+++ b/src/main/java/SQL/RisingTemperature.sql
@@ -0,0 +1,23 @@
+
+--Given a Weather table, write a SQL query to find all dates' Ids with higher temperature compared to its previous (yesterday's) dates.
+--
+--+---------+------------------+------------------+
+--| Id(INT) | RecordDate(DATE) | Temperature(INT) |
+--+---------+------------------+------------------+
+--| 1 | 2015-01-01 | 10 |
+--| 2 | 2015-01-02 | 25 |
+--| 3 | 2015-01-03 | 20 |
+--| 4 | 2015-01-04 | 30 |
+--+---------+------------------+------------------+
+
+
+--+----+
+--| Id |
+--+----+
+--| 2 |
+--| 4 |
+--+----+
+SELECT wt1.Id
+FROM Weather wt1, Weather wt2
+WHERE wt1.Temperature > wt2.Temperature AND
+ TO_DAYS(wt1.RecordDate)-TO_DAYS(wt2.RecordDate)=1;
\ No newline at end of file
diff --git a/src/main/java/SQL/SubjectRanks.sql b/src/main/java/SQL/SubjectRanks.sql
new file mode 100644
index 0000000..bae55fe
--- /dev/null
+++ b/src/main/java/SQL/SubjectRanks.sql
@@ -0,0 +1,36 @@
+
+--+----+-------+
+--| Id | Score |
+--+----+-------+
+--| 1 | 3.50 |
+--| 2 | 3.65 |
+--| 3 | 4.00 |
+--| 4 | 3.85 |
+--| 5 | 4.00 |
+--| 6 | 3.65 |
+--+----+-------+
+
+--+-------+---------+
+--| score | Rank |
+--+-------+---------+
+--| 4.00 | 1 |
+--| 4.00 | 1 |
+--| 3.85 | 2 |
+--| 3.65 | 3 |
+--| 3.65 | 3 |
+--| 3.50 | 4 |
+--+-------+---------+
+
+
+SELECT
+ Score,
+ (SELECT count(distinct Score) FROM Scores WHERE Score >= s.Score) "Rank" -- inner for-loop
+FROM Scores s
+ORDER BY Score desc
+
+
+SELECT
+ Score,
+ (SELECT count(distinct Score) FROM Scores WHERE Score >= s.Score) "Rank"
+FROM Scores s
+ORDER BY Score desc
\ No newline at end of file
diff --git a/src/main/java/SQL/TeamSize.sql b/src/main/java/SQL/TeamSize.sql
new file mode 100644
index 0000000..37cb0c3
--- /dev/null
+++ b/src/main/java/SQL/TeamSize.sql
@@ -0,0 +1,31 @@
+--Employee Table:
+--+-------------+------------+
+--| employee_id | team_id |
+--+-------------+------------+
+--| 1 | 8 |
+--| 2 | 8 |
+--| 3 | 8 |
+--| 4 | 7 |
+--| 5 | 9 |
+--| 6 | 9 |
+--+-------------+------------+
+--Result table:
+--+-------------+------------+
+--| employee_id | team_size |
+--+-------------+------------+
+--| 1 | 3 |
+--| 2 | 3 |
+--| 3 | 3 |
+--| 4 | 1 |
+--| 5 | 2 |
+--| 6 | 2 |
+--+-------------+------------+
+--Employees with Id 1,2,3 are part of a team with team_id = 8. so team_size is 3
+--Employees with Id 4 is part of a team with team_id = 7.
+--Employees with Id 5,6 are part of a team with team_id = 9.
+
+
+# Write your MySQL query statement below
+
+select employee_id, (select count(*) from Employee tb2 where tb2.team_id=tb1.team_id) as team_size
+from Employee tb1
\ No newline at end of file
diff --git a/src/main/java/SQL/Top3Salaries.sql b/src/main/java/SQL/Top3Salaries.sql
new file mode 100644
index 0000000..a5b0a95
--- /dev/null
+++ b/src/main/java/SQL/Top3Salaries.sql
@@ -0,0 +1,19 @@
+--to get to 3 salaries from a table
+-- select * from Employee where salary >= {value} this value we need to calculate dynamically (some min value in top 3 salaries)
+-- so select min(Salary) from (select distinct(salary) from Employee order by Salary DESC limit 3) this will fetch min of top 3 salaries
+-- add this to original query
+--+----+-------------+-------------+
+--| id | Name | Salary |
+--+----+-------------+-------------+
+--| 1 | A | 7000 |
+--| 2 | B | 6000 |
+--| 3 | C | 6000 |
+--| 4 | D | 6000 |
+--| 5 | E | 4000 |
+--| 6 | F | 3000 |
+--| 7 | G | 3000 |
+--| 8 | H | 2000 |
+--| 9 | I | 1000 |
+--+----+-------------+-------------+
+
+select * from Employee where salary >= (select min(Salary) from (select distinct(salary) from Employee order by Salary DESC limit 3))
\ No newline at end of file
diff --git a/src/main/java/SQL/Top3SalaryDepartmentWise.sql b/src/main/java/SQL/Top3SalaryDepartmentWise.sql
new file mode 100644
index 0000000..6f59397
--- /dev/null
+++ b/src/main/java/SQL/Top3SalaryDepartmentWise.sql
@@ -0,0 +1,22 @@
+--
+--Now, for each row of the outer query:
+--OuterDepartmentId, OuterEmployeeSalary is available to the inner query.
+--The inner query will fetch all the salaries that are greater then OuterEmployeeSalary for department matching OuterDepartmentId
+--and return a count of such distinct salaries
+--
+--This count can be 0,1 or 2
+--
+--if 0 -> that means there are no salaries greater then the OuterDepartmentSalary in that department. Hence, it is the greatest salary for that department. And outer query will include that OuterDepartmentId, OuterEmployeeSalary in the output.
+--
+--if 1 -> there is one salary bigger then OuterEmployeeSalary (it is the second largest salary)
+--
+--similarly for count 2, there are two larger salaries.
+
+select d.Name Department, e1.Name Employee, e1.Salary
+from Employee e1
+join Department d
+on e1.DepartmentId = d.Id
+where 3>(select count(distinct(e2.Salary))
+ from Employee e2
+ where e2.Salary > e1.Salary
+ and e1.DepartmentId = e2.DepartmentId) -- the inner query will act as inner for loop which get e.salary from outside O(n^2)
\ No newline at end of file
diff --git a/src/main/java/SQL/TopKthSalary.sql b/src/main/java/SQL/TopKthSalary.sql
new file mode 100644
index 0000000..0f3fe91
--- /dev/null
+++ b/src/main/java/SQL/TopKthSalary.sql
@@ -0,0 +1,5 @@
+SELECT IFNULL((SELECT DISTINCT Salary
+ FROM Employee
+ ORDER BY Salary DESC
+ LIMIT 1,N-1),NULL) AS NthHighestSalary
+
diff --git a/src/main/java/SQL/WinningCandidate.sql b/src/main/java/SQL/WinningCandidate.sql
new file mode 100644
index 0000000..4313ba7
--- /dev/null
+++ b/src/main/java/SQL/WinningCandidate.sql
@@ -0,0 +1,10 @@
+
+
+SELECT Name
+FROM Candidate c
+INNER JOIN (SELECT CandidateId
+ FROM Vote
+ GROUP BY CandidateId
+ ORDER BY COUNT(CandidateId) DESC
+ LIMIT 0,1) v
+ON c.id = v.CandidateId
\ No newline at end of file
diff --git a/src/main/java/backtracking/DistributeStonesInGrid.java b/src/main/java/backtracking/DistributeStonesInGrid.java
new file mode 100644
index 0000000..05c4516
--- /dev/null
+++ b/src/main/java/backtracking/DistributeStonesInGrid.java
@@ -0,0 +1,70 @@
+package backtracking;
+
+/**
+ * https://leetcode.com/problems/minimum-moves-to-spread-stones-over-grid/
+ *
+ * Brute force solution
+ * DFS
+ */
+public class DistributeStonesInGrid {
+ int ret = Integer.MAX_VALUE;
+ public int minimumMoves(int[][] grid) {
+ dfs(grid, 0);
+ return ret;
+ }
+
+ /**
+ * Iterate through all possible pairs of source (cell value > 1) and destination cells (cell value == 0)
+ * in the grid to check if it's possible to move a stone from the source cell to the destination cell.
+ *
+ * Check if the Destination cell is empty (contains 0 stones) and if the Source cell contains more than 1 stone.
+ * Decrease the number of stones in the Source by 1 and increase stones in the Destination cell by 1.
+ * Calculate the Manhattan distance between the Source and the Destination.
+ * Backtracking step: After exploration, restore the original grid configuration, i.e, reverse of step 2.
+ * The count variable keeps track of the minimum number of moves needed to achieve the desired configuration.
+ */
+ private void dfs(int[][] grid, int move) {
+ int zx = -1;
+ int zy = -1;
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (grid[i][j] == 0) {
+ zx = i;
+ zy = j;
+ break;
+
+ }
+ }
+ }
+
+ // this is the base case, because of the constraint
+ if (zx == -1 && zy == -1) {
+ ret = Math.min(ret, move);
+ return;
+ }
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (grid[i][j] > 1) {
+
+ grid[i][j] -= 1;
+ grid[zx][zy] += 1;
+
+ int dx = Math.abs(i - zx);
+ int dy = Math.abs(j - zy);
+
+ dfs(grid, move + dx + dy);
+
+ // the reason we reset is to try all combinations
+ // if the result changes, it means we have found a better solution
+ // line 28 will take care of updating the result
+ grid[i][j] += 1;
+ grid[zx][zy] -= 1;
+
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/binarysearch/AggressiveCows.java b/src/main/java/binarysearch/AggressiveCows.java
new file mode 100644
index 0000000..f3ed02f
--- /dev/null
+++ b/src/main/java/binarysearch/AggressiveCows.java
@@ -0,0 +1,67 @@
+package binarysearch;
+
+// https://takeuforward.org/data-structure/aggressive-cows-detailed-solution/
+
+import java.util.Arrays;
+
+/**
+ * Example 1:
+ * Input Format:
+ * N = 6, k = 4, arr[] = {0,3,4,7,10,9}
+ * Result:
+ * 3
+ * Explanation:
+ * The maximum possible minimum distance between any two cows will be 3 when 4 cows are placed at positions {0, 3, 7, 10}.
+ * Here the distances between cows are 3, 4, and 3 respectively.
+ * We cannot make the minimum distance greater than 3 in any ways.
+ */
+public class AggressiveCows {
+
+ public int aggressiveCows(int[] stalls, int cows){
+ //To arrange the cows in a consecutive manner while ensuring a certain distance between them,
+ // the initial step is to sort the stalls based on their positions.
+ // In a sorted array, the minimum distance will always be obtained from any two consecutive cows
+ Arrays.sort(stalls);
+ //The minimum possible distance between two cows is 1 as the minimum distance between 2 consecutive stalls is 1.
+ //The maximum possible distance between two cows is = max(stalls[])-min(stalls[]). This case occurs when we place 2 cows at two ends of the sorted stalls array.
+ int right = stalls[stalls.length-1] - stalls[0];
+ int left=1;
+
+ while(left= distance){
+ count++;
+ lastPosition = stalls[j];
+ }
+ }
+
+ return count >= cows;
+ }
+}
diff --git a/src/main/java/binarysearch/AssignBooks.java b/src/main/java/binarysearch/AssignBooks.java
new file mode 100644
index 0000000..643b4d4
--- /dev/null
+++ b/src/main/java/binarysearch/AssignBooks.java
@@ -0,0 +1,45 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+// https://leetcode.com/problems/split-array-largest-sum/
+//https://takeuforward.org/data-structure/allocate-minimum-number-of-pages/
+public class AssignBooks {
+
+ private static int getPieces(int[] nums, int mid) {
+ int sum = 0; // Current sum of the subarray
+ int pieces = 1; // At least one subarray is needed
+
+ for (int num : nums) {
+ if (sum + num > mid) { // If adding num to current sum exceeds mid
+ sum = num; // Start a new subarray
+ pieces++; // Increase the count of subarrays
+ } else {
+ sum += num; // Continue adding to the current subarray
+ }
+ }
+ return pieces;
+ }
+
+ public int splitArray(int[] nums, int k) {
+ // Initial boundary values for binary search
+ int start = Arrays.stream(nums).max().orElse(0); // The minimum possible largest sum is the max element in the array
+ int end = Arrays.stream(nums).sum(); // The maximum possible largest sum is the sum of all elements in the array
+
+ // Binary search for the minimum possible largest sum
+ while (start < end) {
+ int mid = start + (end - start) / 2; // Middle value between start and end
+ int pieces = getPieces(nums, mid);
+
+ // If more subarrays are needed than allowed, increase the lower bound
+ if (pieces > k) {
+ start = mid + 1; // Increase the lower bound since mid is too small
+ } else {
+ end = mid; // Decrease the upper bound since mid could be the answer
+ }
+ }
+
+ // When start == end, we've found the minimum possible largest sum
+ return start; // or return end; since start == end
+ }
+}
diff --git a/src/main/java/binarysearch/BinarySearchTemplate.java b/src/main/java/binarysearch/BinarySearchTemplate.java
new file mode 100644
index 0000000..98f37bd
--- /dev/null
+++ b/src/main/java/binarysearch/BinarySearchTemplate.java
@@ -0,0 +1,48 @@
+package binarysearch;
+
+public class BinarySearchTemplate {
+
+ /**
+ * while (left < right):
+ * This condition is typically used when you want to find the insertion point or a specific boundary in a sorted array.
+ * It's often used when you're not necessarily looking for an exact match,
+ * but rather a position where an element should be inserted to maintain the sorted order.
+ * while (left <= right):
+ * This condition is used when you're searching for a specific element in the array
+ * and want to return its index if found.
+ * It allows the search to continue until the pointers cross each other, ensuring that every element is checked.
+
+ * The key differences are:
+ *
+ * Termination condition:
+ *
+ * left < right will terminate when left == right
+ * left <= right will terminate when left > right
+ *
+ * Final state:
+ *
+ * With left < right, left will be the insertion point or boundary you're looking for
+ * With left <= right, you need to check if the element was found after the loop ends
+ *
+ * Use case:
+ *
+ * left < right is often used for problems like finding the first/last occurrence of an element, or finding an insertion point
+ * left <= right is typically used when you're searching for a specific element and want to return its index
+ *
+ */
+
+// public T template(int n) {
+//
+// int left= min_val;
+// int right= max_val;
+//
+// while(left...
+ *
+ * @param arr
+ * @return
+ */
+ public boolean validMountainArray(int[] arr) {
+ int left = 0;
+ int right = arr.length;
+ int peak = -1;
+ while (left <= right) {
+ int mid = left + (right - left) / 2;
+ System.out.println("mid: " + mid);
+ if (mid > 0 && arr[mid] > arr[mid - 1] && mid < arr.length - 1 && arr[mid + 1] < arr[mid]) {
+ peak = mid;
+ break;
+ }
+
+ if (mid < arr.length - 1 && arr[mid] < arr[mid + 1]) {
+ left = mid + 1;
+ } else {
+ right = mid - 1;
+ }
+ }
+
+ if (peak == -1)
+ return false;
+ for (int i = 0; i < peak; i++) {
+ if (arr[i] >= arr[i + 1])
+ return false;
+ }
+ // peak to n - 1
+ for (int i = peak; i < arr.length - 1; i++) {
+ if (arr[i] <= arr[i + 1])
+ return false;
+ }
+ return true;
+ }
+
+ //https://leetcode.com/problems/find-peak-element
+ public int findPeakElement(int[] nums) {
+ //if(nums.length)
+ int left = 0;
+ int right = nums.length - 1;
+
+ while (left <= right) {
+ int mid = (left + right) / 2;
+ if ((mid == 0 || nums[mid - 1] < nums[mid]) && (mid == nums.length - 1 || nums[mid + 1] < nums[mid])) {
+ return mid;
+ } else if (mid == 0 || nums[mid - 1] < nums[mid] && nums[mid + 1] > nums[mid]) {
+ left = mid + 1;
+ } else {
+ right = mid - 1;
+ }
+ }
+ return -1;
+ }
+
+ //https://leetcode.com/problems/peak-index-in-a-mountain-array/description/
+ public int peakIndexInMountainArray(int[] arr) {
+
+ int left = 0;
+ int right = arr.length - 1;
+
+ while (left <= right) {
+ int mid = left + (right - left) / 2;
+ if (arr[mid] > arr[mid - 1] && (arr[mid] > arr[mid + 1] || mid == arr.length - 1)) {
+ return mid;
+ }
+ if (arr[mid] > arr[mid - 1]) {
+ left = mid + 1;
+ } else {
+ right = mid;
+ }
+ }
+
+ return -1;
+ }
+
+ //https://leetcode.com/problems/find-in-mountain-array/
+ public int findInMountainArray(int target, MountainArray mountainArr) {
+ int left = 0;
+ int n = mountainArr.length();
+ int right = n - 1;
+ int peak = 0;
+ int mid = 0;
+ while (left < right) {
+ mid = (left + right) / 2;
+ if (mountainArr.get(mid) < mountainArr.get(mid + 1)) {
+ left = mid + 1;
+
+ } else {
+ right = mid;
+ }
+ }
+ peak = left;
+ left = 0;
+ right = peak;
+
+ while (left <= right) {
+ mid = (left + right) / 2;
+ if (mountainArr.get(mid) < target) {
+ left = mid + 1;
+ } else if (mountainArr.get(mid) > target) {
+ right = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+
+ left = peak;
+ right = n - 1;
+
+ while (left <= right) {
+ mid = (left + right) / 2;
+ if (mountainArr.get(mid) > target) {
+ left = mid + 1;
+ } else if (mountainArr.get(mid) < target) {
+ right = mid - 1;
+ } else {
+ return mid;
+ }
+ }
+
+ return -1;
+
+ }
+
+ //https://leetcode.com/problems/longest-mountain-in-array
+ // O(N) solution is fine for this constraint
+ public int longestMountain(int[] A) {
+ if (A == null || A.length < 3)
+ return 0;
+ int ans = 0;
+ for (int i = 1; i < A.length - 1; i++) {
+ if (A[i] > A[i - 1] && A[i] > A[i + 1]) { // i is a peak
+ int left = i - 1; // find leftmost of the peak
+ while (left > 0 && A[left - 1] < A[left])
+ left--;
+
+ int right = i + 1; // find rightmost of the peak
+ while (right < A.length - 1 && A[right + 1] < A[right])
+ right++;
+
+ ans = Math.max(ans, right - left + 1); // get the width using left and rightmost
+
+ }
+ }
+ return ans;
+ }
+
+ //https://leetcode.com/problems/find-peak-element-ii/
+ // https://youtu.be/nGGp5XBzC4g
+ public int[] findPeakGrid(int[][] mat) {
+
+ int left = 0;
+ int right = mat[0].length;
+ int m = mat.length;
+ //In this scenario, we'll employ binary search within the columns of the matrix.
+ // Since the peak element is guaranteed to exist in one of the columns,
+ // our search range will span from 0 to M, where M represents the total number of columns.
+ int n = mat[0].length;
+ while (left <= right) {
+ int mid = (left + right) / 2;
+ //Find the largest element in the ‘mid’ column: We will use the function findMaxIndex()
+ // to find the largest element of the mid-th column and the function will return the row number
+ int maxRow = getMaxElementRow(mat, mid);
+
+ int prev = mid - 1 >= 0 ? mat[maxRow][mid - 1] : -1;
+ int next = mid + 1 < n ? mat[maxRow][mid + 1] : -1;
+
+ //If matrix[maxRowIndex][mid] > matrix[maxRowIndex][mid-1] && matrix[maxRowIndex][mid] > matrix[maxRowIndex][mid+1]:
+ // This means matrix[maxRowIndex][mid] is the peak element. So, we will return its location
+ if (mat[maxRow][mid] > prev && mat[maxRow][mid] > next) {
+ return new int[]{maxRow, mid};
+ }
+ //For example, if matrix[i][j-1] is greater than the chosen largest element matrix[i][j],
+ // we can conclude that matrix[i][j-1] is also greater than all the elements of the j-th column.
+ // This is because matrix[i][j] is the largest element of j-th column.
+ // Thus matrix[i][j-1] is now more likely to be the peak element.
+ // The logic is also applied to matrix[i][j+1]. This is how the elimination is working.
+ if (mat[maxRow][mid] < next) {
+
+ left = mid + 1;
+ } else {
+ //If matrix[maxRowIndex][mid] < matrix[maxRowIndex][mid-1]: As we are in the right half of the peak element,
+ // we have to eliminate this right half (i.e. high = mid-1). Because our peak element appears somewhere on the left side.
+ right = mid - 1;
+ }
+ }
+
+ return new int[]{-1, -1};
+
+ }
+
+ public int getMaxElementRow(int[][] mat, int col) {
+
+ int rowNum = -1;
+ int maxElem = Integer.MIN_VALUE;
+ for (int i = 0; i < mat.length; i++) {
+ //Although every element of the selected column might be a peak element,
+ // the largest number has always the highest possibility of being one.
+ // That is why, to reduce the checking operation, we are selecting the largest number.
+ if (mat[i][col] > maxElem) {
+ maxElem = mat[i][col];
+ rowNum = i;
+ }
+ }
+
+ return rowNum;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/binarysearch/BoatsToSave.java b/src/main/java/binarysearch/BoatsToSave.java
new file mode 100644
index 0000000..fa5a759
--- /dev/null
+++ b/src/main/java/binarysearch/BoatsToSave.java
@@ -0,0 +1,36 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+/**
+ * The i-th person has weight people[i],
+ * and each boat can carry a maximum weight of limit.
+ * Each boat carries at most 2 people at the same time,
+ * provided the sum of the weight of those people is at most limit.
+ * Return the minimum number of boats to carry every given person.
+ * (It is guaranteed each person can be carried by a boat.)
+ */
+class BoatsToSave {
+ public int numRescueBoats(int[] people, int limit) {
+ if (people.length == 0 || limit == 0) return 0;
+
+ Arrays.sort(people);
+
+ int i = 0;
+ int j = people.length - 1;
+ int res = 0;
+ while (i <= j) {
+ if (people[i] + people[j] <= limit) {
+ res++;
+ i++;
+ j--;
+ } else {
+ res++;
+ j--;// neglecting people with more weight
+ }
+
+ }
+
+ return res;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/binarysearch/FindMinimumInRotatedArray.java b/src/main/java/binarysearch/FindMinimumInRotatedArray.java
new file mode 100644
index 0000000..eb8f598
--- /dev/null
+++ b/src/main/java/binarysearch/FindMinimumInRotatedArray.java
@@ -0,0 +1,59 @@
+package binarysearch;
+
+/**
+ * https://leetcode.com/problems/find-minimum-in-rotated-sorted-array/
+ */
+public class FindMinimumInRotatedArray {
+
+ public static int findMin(int[] nums) {
+ if (nums.length == 0) {
+ return -1;
+ }
+ if (nums.length == 1) {
+ return nums[0];
+ }
+ int start = 0;
+ int end = nums.length - 1;
+ while (start < end) {
+ int mid = ((end - start) / 2) + start;
+
+ if (nums[start] <= nums[end]) {
+ return nums[start];
+ }
+ // mid is compared against end, if mid is high, then the rotated part is right of mid
+ if (nums[mid] < nums[end]) {
+ end = mid;
+ } else {
+ start = mid + 1;
+ }
+ }
+ return -1;
+ }
+
+ public int findMinWithDuplicate(int[] nums) {
+ if (nums.length == 1) return nums[0];
+ int start = 0;
+ int end = nums.length - 1;
+ while (start < end) {
+
+ if (nums[start] == nums[end]) {
+ start++; // conservative approach that ensures we don't accidentally skip over the minimum element.
+ } else {
+ int mid = start + (end - start) / 2;
+ if (nums[mid] > nums[end]) {
+ start = mid + 1;
+ } else {
+ end = mid;
+ }
+ }
+
+ }
+
+ return nums[start];
+ }
+
+ public static void main(String[] args) {
+ int[] arr = {7, 1, 2, 3, 4, 5, 6};
+ findMin(arr);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/binarysearch/FindSmallestDivisor.java b/src/main/java/binarysearch/FindSmallestDivisor.java
new file mode 100644
index 0000000..df2cf2e
--- /dev/null
+++ b/src/main/java/binarysearch/FindSmallestDivisor.java
@@ -0,0 +1,32 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold/
+ */
+public class FindSmallestDivisor {
+ public int smallestDivisor(int[] nums, int threshold) {
+ int left = 1;
+ int right = Arrays.stream(nums).max().orElse(0);
+
+ while (left < right) {
+ int mid = left + (right - left) / 2;
+ if (isFeasible(nums, mid, threshold)) {
+ right = mid;
+ } else {
+ left = mid + 1;
+ }
+ }
+
+ return left;
+ }
+
+ public boolean isFeasible(int[] nums, int mid, int threshold) {
+ int total = 0;
+ for (int num : nums) {
+ total += (int) Math.ceil((double) num / mid);
+ }
+ return total <= threshold;
+ }
+}
diff --git a/src/main/java/binarysearch/FirstAndLastOccurence.java b/src/main/java/binarysearch/FirstAndLastOccurence.java
new file mode 100644
index 0000000..1529edf
--- /dev/null
+++ b/src/main/java/binarysearch/FirstAndLastOccurence.java
@@ -0,0 +1,81 @@
+package binarysearch;
+
+/**
+ * https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/submissions/
+ */
+public class FirstAndLastOccurence {
+
+ public int[] searchRange(int[] nums, int target) {
+ int[] result = new int[]{-1, -1};
+ if (nums.length == 0) return result;
+
+ int first = binarySearch(nums, target);
+
+ if (first == nums.length || nums[first] != target) return result;
+
+ result[0] = first;
+ int last = binarySearch(nums, target + 1);
+
+ result[1] = nums[last] == target ? last : last - 1;
+
+ return result;
+
+ }
+
+ public int binarySearch(int[] nums, int target) {
+ int left = 0;
+ int right = nums.length - 1;
+
+ while (left < right) {
+ int mid = left + (right - left) / 2;
+
+ if (nums[mid] >= target) {
+ right = mid;
+ } else {
+ left = mid + 1;
+
+ }
+ }
+
+ return left;
+ }
+ public int[] searchRangeII(int[] nums, int target) {
+ int low = 0;
+ int high = nums.length - 1;
+ int[] ans = {-1 , -1};
+
+ if(nums.length < 1){
+ return ans;
+ }
+ while(low <= high){ //Binary search for 1st occurrence
+ int mid = (low + high)/2;
+ if(target == nums[mid]){
+ ans[0] = mid;
+ high = mid -1; //searching on the left half
+ }
+ else if(target > nums[mid]){
+ low = mid + 1;
+ }
+ else{
+ high = mid - 1;
+ }
+ }
+
+ low = 0; //Binary search for 2nd occurrence
+ high = nums.length - 1;
+ while(low <= high){
+ int mid = (low + high)/2;
+ if(target == nums[mid]){
+ ans[1] = mid;
+ low = mid + 1; //searching on the right half
+ }
+ else if(target > nums[mid]){
+ low = mid + 1;
+ }
+ else{
+ high = mid - 1;
+ }
+ }
+ return ans;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/binarysearch/FirstBadVersion.java b/src/main/java/binarysearch/FirstBadVersion.java
new file mode 100644
index 0000000..a2da91c
--- /dev/null
+++ b/src/main/java/binarysearch/FirstBadVersion.java
@@ -0,0 +1,25 @@
+package binarysearch;
+
+/**
+ * https://leetcode.com/problems/first-bad-version/
+ */
+public class FirstBadVersion {
+
+ public int firstBadVersion(int n) {
+ if(n==0) return 0;
+ int left=1;
+ int right=n;
+
+ while(left...
+ *
+ * one of the trick involved in computing rage queries over prefix sum is use the given query index to calculate the prefix-sum for ex
+ *
+ * if queries are from index (1 , 5) value is 4 and from index (3,7) value is 6, then the prefix array would look like
+ * [0,5,0,6,0,0,-5,0,0,-6,0,0] => when prefix sum is calculated then the array would get transformed to [0,5,5,11,11,11,6,6,6,0,0,0]
+ * the advantage is update query run time is O(1) as we are touching the specific index at that point, when get query comes we have to traverse the array and it's complexity is O(N)
+ *
+ * we can improve the above array storage space by removing 0 entries with the help of sparse array(a simple hashmap to store index and value at that place)
+ */
+public class FlowerBloomSparseArray {
+ // Blooming flowers = started flowers - ended flowers
+ // Collect start bloom time point array, then sort it.
+ //Collect end bloom time point array, then sort it.
+ // For each time point t in persons:
+ //
+ //Binary search the upper bound of t in start, then we find the started flowers.
+ //Binary search the lower bound of t in end, then we find the started flowers.
+ //Blooming flowers = started flowers - ended flowers
+ public static int[] fullBloomFlowersBinarySearch(int[][] flowers, int[] people) {
+ List starts = new ArrayList<>();
+ List ends = new ArrayList<>();
+
+
+ for (int[] flower: flowers) {
+ starts.add(flower[0]);
+ ends.add(flower[1] + 1); // Note that a flower = [start, end] stops blooming at end + 1, not end.
+ }
+
+ Collections.sort(starts);
+ Collections.sort(ends);
+ int[] ans = new int[people.length];
+
+ for (int index = 0; index < people.length; index++) {
+ int person = people[index];
+ int i = binarySearch(starts, person);
+ int j = binarySearch(ends, person);
+ ans[index] = i - j;
+ }
+
+ return ans;
+ }
+
+ public static int binarySearch(List arr, int target) {
+ int left = 0;
+ int right = arr.size();
+ while (left < right) {
+ int mid = (left + right) / 2;
+ if (target < arr.get(mid)) {
+ right = mid;
+ } else {
+ left = mid + 1;
+ }
+ }
+
+ return left;
+ }
+
+
+ public static void main(String[] args) {
+ fullBloomFlowersBinarySearch(new int[][]{{1, 6}, {3, 7}, {9, 12}, {4, 13}}, new int[]{2, 3, 7, 11});
+ }
+
+ public int[] fullBloomFlowers(int[][] flowers, int[] persons) {
+ int BLOOM = 0, WILT = 1, PERSON = 2;
+ int[] arr = new int[persons.length];
+ PriorityQueue pq = new PriorityQueue<>((a,b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
+ for (int[] flower : flowers) {
+ pq.offer(new int[]{flower[0], BLOOM});
+ pq.offer(new int[]{flower[1], WILT});
+ }
+ for(int i = 0; i < persons.length; i++){
+ pq.offer(new int[]{persons[i],PERSON,i});
+ }
+ int count = 0;
+ while(!pq.isEmpty()){
+ int[] temp = pq.poll();
+
+ if(temp[1] == BLOOM) count++;
+ else if(temp[1] == WILT) count--;
+ else{
+ arr[temp[2]] = count;
+ }
+ }
+ return arr;
+ }
+}
diff --git a/src/main/java/binarysearch/KClosestElements.java b/src/main/java/binarysearch/KClosestElements.java
new file mode 100644
index 0000000..3326822
--- /dev/null
+++ b/src/main/java/binarysearch/KClosestElements.java
@@ -0,0 +1,113 @@
+package binarysearch;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * https://leetcode.com/problems/find-k-closest-elements/
+ * Revise
+ */
+public class KClosestElements {
+ /**
+ * Now let's see how x - arr[mid] > arr[mid + k] - x works:
+ * Say this array is sorted from small to large: [x1, arr[mid], x2, arr[mid + k], x3]
+ *
+ * Case x1:
+ * x1 is smaller than both arr[mid] and arr[mid + k]. We should recurse into the left.
+ * x - arr[mid] is negative and arr[mid + k] - x is positive.
+ * The condition is false and we recurse to left.
+ *
+ * Case x2:
+ * x2 is in between arr[mid] and arr[mid + k]. We should recurse to the side that is closer to x.
+ * x - arr[mid] and arr[mid + k] - x are both positive.
+ * The comparison works the same as using abs(); we recursive to the closer side.
+ * (When in the case of arr[mid] == arr[mid + k], the condition is false and we recurse to the left.)
+ *
+ * Case x3:
+ * x3 is larger than both arr[mid] and arr[mid + k]. We should recurse into the right.
+ * x - arr[mid] is positive and arr[mid + k] - x is negative.
+ * The condition is true and we recurse to right.
+ * Now the previously failed corner case arr[mid] == arr[mid + k] < x3 doesn't cause a problem anymore
+ * because the positivity of the numbers we're comparing is still the same.
+ */
+ public List findClosestElements(int[] arr, int k, int x) {
+ // Initialize binary search bounds
+ // we need to find the left most element which will be the start of the result set
+ int left = 0;
+ // the farthest it can go is array-k
+ int right = arr.length - k; // else the mid+k will go out of bound
+
+ // Binary search against the criteria described
+ while (left < right) {
+ int mid = (left + right) / 2;
+ // If the element at arr[mid] is closer to x than arr[mid + k],
+ // then that means arr[mid + k], as well as every element to the right of it can never be in the answer.
+ // This means we should move our right pointer to avoid considering them
+ if (x - arr[mid] > arr[mid + k] - x) {
+ left = mid + 1;
+ } else {
+ right = mid;
+ }
+ }
+
+ // Create output in correct format
+ List result = new ArrayList<>();
+ for (int i = left; i < left + k; i++) {
+ result.add(arr[i]);
+ }
+
+ return result;
+ }
+
+ public List findClosestElementsIntuitive(int[] arr, int k, int x) {
+ int left = 0, right = arr.length - 1, mid;
+ List res = new ArrayList<>();
+
+ while (left < right) {
+ mid = (left + right) / 2;
+ if (arr[mid] >= x) {
+ right = mid;
+ } else {
+ left = mid + 1;
+ }
+ }
+ int leftPointer = left - 1;
+ int rightPointer = left;
+
+ while (rightPointer - leftPointer <= k) {
+ if (leftPointer < 0) {
+ rightPointer += 1;
+ continue;
+ }
+ if (rightPointer == arr.length || Math.abs(arr[leftPointer] - x) <= Math.abs(arr[rightPointer] - x)) {
+ leftPointer -= 1;
+ } else {
+ rightPointer += 1;
+ }
+ }
+
+ for (int i = leftPointer + 1; i < rightPointer; i++) {
+ res.add(arr[i]);
+ }
+
+ return res;
+ }
+
+ public List findClosestElementsTwoPointers(int[] arr, int k, int x) {
+ int lo = 0;
+ int hi = arr.length - 1;
+ while (hi - lo >= k) {
+ if (Math.abs(arr[lo] - x) > Math.abs(arr[hi] - x)) {
+ lo++;
+ } else {
+ hi--;
+ }
+ }
+ List result = new ArrayList<>(k);
+ for (int i = lo; i <= hi; i++) {
+ result.add(arr[i]);
+ }
+ return result;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/binarysearch/KokoEatingBananas.java b/src/main/java/binarysearch/KokoEatingBananas.java
new file mode 100644
index 0000000..9066645
--- /dev/null
+++ b/src/main/java/binarysearch/KokoEatingBananas.java
@@ -0,0 +1,41 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/koko-eating-bananas/
+ */
+public class KokoEatingBananas {
+
+ public int minEatingSpeed(int[] piles, int h) {
+
+ int left = 1;
+ // if you feel this would take O(N) then take the max value
+ // given as part of problem constraint
+
+ int right = Arrays.stream(piles).max().orElse(0);
+
+ while (left < right) {
+ int mid = left + (right - left) / 2;
+
+ if (isFeasible(piles, mid, h)) {
+ right = mid;
+ } else {
+ left = mid + 1;
+ }
+ }
+
+ return left;
+
+ }
+
+ public boolean isFeasible(int[] piles, int mid, int h) {
+ int time = 0;
+
+ for (int p : piles) {
+ time += (int) Math.ceil((double) (p) / (double) (mid));
+ }
+
+ return time <= h;
+ }
+}
diff --git a/src/main/java/binarysearch/KthMissingPositive.java b/src/main/java/binarysearch/KthMissingPositive.java
new file mode 100644
index 0000000..5359c0c
--- /dev/null
+++ b/src/main/java/binarysearch/KthMissingPositive.java
@@ -0,0 +1,24 @@
+package binarysearch;
+
+public class KthMissingPositive {
+
+ public int findKthPositive(int[] arr, int k) {
+ int left = 0;
+ int right = arr.length; //Initialize right to arr.length instead of arr.length - 1.
+ // This allows the search to consider the position just after the array's end.
+ //[1,2,3,4], k = 2, the answer is 6, not 5.
+
+ while (left < right) {
+ int mid = left + (right - left) / 2;
+
+ int diff = arr[mid] - (mid + 1);
+ if (diff < k) {
+ left = mid + 1;
+ } else {
+ right = mid;
+ }
+ }
+
+ return left + k;
+ }
+}
diff --git a/src/main/java/binarysearch/KthSmallestFromTwoSortedArrays.java b/src/main/java/binarysearch/KthSmallestFromTwoSortedArrays.java
new file mode 100644
index 0000000..0d76e4c
--- /dev/null
+++ b/src/main/java/binarysearch/KthSmallestFromTwoSortedArrays.java
@@ -0,0 +1,49 @@
+package binarysearch;
+
+/**
+ * this is same as median for 2 sorted arrays, with little bit modification
+ *
+ */
+class KthSmallestFromTwoSortedArrays {
+
+
+ public double findKthSmallestFromSortedArrays(int[] input1, int[] input2, int k) {
+ //if input1 length is greater than switch them so that input1 is smaller than input2.
+ // the reason is to do binary search on smaller array to reduce time complexity
+ if (input1.length > input2.length) {
+ return findKthSmallestFromSortedArrays(input2, input1,k);
+ }
+ int x = input1.length;
+ int y = input2.length;
+ int n = x + y;
+
+ int low = 0;
+ int high = x;
+ while (low <= high) {
+ int mid1 = (low + high) / 2;
+ int mid2 = k - mid1;
+
+ int left1 = (mid1 == 0) ? Integer.MIN_VALUE : input1[mid1 - 1];
+ int right1 = (mid1 == x) ? Integer.MAX_VALUE : input1[mid1];
+ int left2 = (mid2 == 0) ? Integer.MIN_VALUE : input2[mid2 - 1];
+ int right2 = (mid2 == y) ? Integer.MAX_VALUE : input2[mid2];
+
+ if (left1 <= right2 && left2 <= right1) {
+ return Math.max(left1, left2);
+ } else if (left1 > right2) {
+ //If l1 > r2: This implies that we have considered more elements from arr1[] than necessary.
+ // So, we have to take less elements from arr1[] and more from arr2[].
+ // In such a scenario, we should try smaller values of x.
+ // To achieve this, we will eliminate the right half (high = mid-1).
+ high = mid1 - 1;
+ }
+ //This implies that we have considered more elements from arr2[] than necessary.
+ // So, we have to take less elements from arr2[] and more from arr1[].
+ // In such a scenario, we should try bigger values of x.
+ // To achieve this, we will eliminate the left half (low = mid+1).
+ else low = mid1 + 1;
+
+ }
+ return -1.0;
+ }
+}
diff --git a/src/main/java/binarysearch/KthSmallestInMultiplicationTable.java b/src/main/java/binarysearch/KthSmallestInMultiplicationTable.java
new file mode 100644
index 0000000..b07b03e
--- /dev/null
+++ b/src/main/java/binarysearch/KthSmallestInMultiplicationTable.java
@@ -0,0 +1,72 @@
+package binarysearch;
+
+/**
+ * https://leetcode.com/problems/kth-smallest-number-in-multiplication-table/
+ *
+ * For Kth-Smallest problems like this, what comes to our mind first is Heap.
+ * Usually we can maintain a Min-Heap and just pop the top of the Heap for k times.
+ * However, that doesn't work out in this problem.
+ * We don't have every single number in the entire Multiplication Table, instead, we only have the height and the length of the table.
+ * If we are to apply Heap method, we need to explicitly calculate these m * n values and save them to a heap.
+ * The time complexity and space complexity of this process are both O(mn), which is quite inefficient.
+ * This is when binary search comes in. Remember we say that designing condition function is the most difficult part?
+ * In order to find the k-th smallest value in the table, we can design an enough function,
+ * given an input num, determine whether there're at least k values less than or equal to num.
+ * The minimal num satisfying enough function is the answer we're looking for.
+ * Recall that the key to binary search is discovering monotonicity.
+ * In this problem, if num satisfies enough, then of course any value larger than num can satisfy.
+ * This monotonicity is the fundament of our binary search algorithm.
+ */
+public class KthSmallestInMultiplicationTable {
+
+ public int findKthNumber(int m, int n, int k) {
+ int left=1;
+ int right= m*n;
+
+ while(left=k if yes adjust the right side
+ int temp= Math.min(mid/i,n);
+ System.out.println("I :: "+i+" N:: "+n+" MID/N ::"+temp);
+ count+=temp;
+ }
+ System.out.println("isFeasible end:: "+count);
+ System.out.println();
+ return count>=k;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(new KthSmallestInMultiplicationTable().findKthNumber(4,4,6));
+ }
+}
diff --git a/src/main/java/binarysearch/MagneticForceBetweenTwoBalls.java b/src/main/java/binarysearch/MagneticForceBetweenTwoBalls.java
new file mode 100644
index 0000000..c31d1c3
--- /dev/null
+++ b/src/main/java/binarysearch/MagneticForceBetweenTwoBalls.java
@@ -0,0 +1,52 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/magnetic-force-between-two-balls/
+ *
+ * same as aggressive cows
+ */
+public class MagneticForceBetweenTwoBalls {
+
+
+ public static void main(String[] args) {
+ new MagneticForceBetweenTwoBalls().maxDistance(new int[]{1, 2, 3, 4, 7}, 3);
+ }
+
+ /*minimum magnetic force between any two balls is maximum means
+ ex: 1 2 3 4 7
+ . . . min magnetic force is 1 min is 1
+ . . . min magnetic force is 2 min is 1
+ . . . min magnetic force is 3 *
+ we should maximise the minimum magnetic force
+ minimum magnetic must come 1 from all cases and if we have maximise it then it will come as 3 3 6
+ */
+ public int maxDistance(int[] position, int m) {
+ int n = position.length;
+ Arrays.sort(position);
+ int left = 1, right = position[n - 1] - position[0];
+ while (left <= right) {
+ int mid = left + (right - left) / 2;
+ if (check(position, mid, m))
+ left = mid + 1;
+ else
+ right = mid - 1;
+ }
+ //When the binary search ends, right will be the largest distance that satisfies the condition,
+ // and left will be one more than this value.
+ return right;
+ }
+
+ private boolean check(int[] arr, int mid, int m) {
+ int count = 1, last = arr[0];
+ for (int i = 1; i < arr.length; i++) {
+ if (arr[i] - last >= mid) {
+ count++;
+ last = arr[i];
+ if (count >= m) return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/binarysearch/MaxSoldiers.java b/src/main/java/binarysearch/MaxSoldiers.java
new file mode 100644
index 0000000..1e1d0c9
--- /dev/null
+++ b/src/main/java/binarysearch/MaxSoldiers.java
@@ -0,0 +1,53 @@
+package binarysearch;
+
+import java.util.PriorityQueue;
+
+/**
+ * https://leetcode.com/problems/the-k-weakest-rows-in-a-matrix/
+ */
+public class MaxSoldiers {
+ static class Pair {
+ T row;
+ S soldiers;
+
+ Pair(T row, S soldiers) {
+ this.row = row;
+ this.soldiers = soldiers;
+ }
+ }
+
+ public int[] kWeakestRows(int[][] mat, int k) {
+ int[] result = new int[k];
+ PriorityQueue> queue = new PriorityQueue<>(
+ (a, b) -> a.soldiers.equals(b.soldiers) ? Integer.compare(a.row, b.row)
+ : Integer.compare(a.soldiers, b.soldiers));
+ int i = 0;
+ for (int[] rows : mat) {
+ int temp = binarySearchUtil(rows, 0, rows.length);
+ queue.offer(new Pair<>(i, temp));
+ i++;
+ }
+ int ind = 0;
+ while (ind < k) {
+ result[ind++] = queue.poll().row;
+ }
+ return result;
+
+ }
+
+ public int binarySearchUtil(int[] row, int start, int end) {
+ int lo = 0;
+ int hi = row.length;
+
+ while (lo < hi) {
+ int mid = lo + (hi - lo) / 2;
+
+ if (row[mid] == 1)
+ lo = mid + 1;
+ else
+ hi = mid;
+ }
+
+ return lo;
+ }
+}
diff --git a/src/main/java/binarysearch/MaximumDistanceBetweenGasStation.java b/src/main/java/binarysearch/MaximumDistanceBetweenGasStation.java
new file mode 100644
index 0000000..8ae0098
--- /dev/null
+++ b/src/main/java/binarysearch/MaximumDistanceBetweenGasStation.java
@@ -0,0 +1,128 @@
+package binarysearch;
+
+// https://leetcode.com/problems/minimize-max-distance-to-gas-station
+// https://takeuforward.org/arrays/minimise-maximum-distance-between-gas-stations/
+// extreme tricky hard problem
+
+/**
+ * You are given a sorted array ‘arr’ of length ‘n’, which contains positive integer positions of ‘n’ gas stations on the X-axis.
+ * You are also given an integer ‘k’. You have to place 'k' new gas stations on the X-axis.
+ * You can place them anywhere on the non-negative side of the X-axis, even on non-integer positions.
+ * Let 'dist' be the maximum value of the distance between adjacent gas stations after adding k new gas stations.
+ * Find the minimum value of ‘dist’.
+ *
+ * Input Format:
+ * N = 5, arr[] = {1,2,3,4,5}, k = 4
+ * Result:
+ * 0.5
+ * Explanation:
+ * One of the possible ways to place 4 gas stations is {1,1.5,2,2.5,3,3.5,4,4.5,5}.
+ * Thus the maximum difference between adjacent gas stations is 0.5.
+ * Hence, the value of ‘dist’ is 0.5. It can be shown that there is no possible way to add 4 gas stations in such a way that the value of ‘dist’ is lower than this.
+ */
+public class MaximumDistanceBetweenGasStation {
+
+ public double minimiseMaxDistanceBruteForce(int[] stations, int k) {
+ int n = stations.length;
+ int[] howManyLeft = new int[n - 1];
+
+ for (int gasStations = 1; gasStations <= k; gasStations++) {
+ double maxSelection = -1;
+ int maxIndex = -1;
+
+ for (int i = 0; i < n - 1; i++) {
+ double diff = (stations[i + 1] - stations[i]);
+ double selectionLength = diff / (howManyLeft[i] + 1);
+ if (selectionLength > maxSelection) {
+ maxSelection = selectionLength;
+ maxIndex = i;
+ }
+ }
+ howManyLeft[maxIndex]++;
+ }
+
+ double maxDistance = -1;
+ for (int i = 0; i < n - 1; i++) {
+ double diff = (stations[i + 1] - stations[i]);
+ double selectionLength = diff / (howManyLeft[i] + 1);
+ maxDistance = Math.max(maxDistance, selectionLength);
+ }
+
+ return maxDistance;
+ }
+
+ public double minimiseMaxDistanceHeap(int[] stations, int k) {
+ int n = stations.length;
+ int[] howManyLeft = new int[n - 1];
+
+ var priorityQueue = new java.util.PriorityQueue((a, b) -> Double.compare(b[0], a[0]));
+
+ for (int i = 0; i < n - 1; i++) {
+ double diff = (stations[i + 1] - stations[i]);
+ priorityQueue.add(new double[]{diff, i});
+ }
+
+ for (int gasStations = 1; gasStations <= k && !priorityQueue.isEmpty(); gasStations++) {
+ double[] curr = priorityQueue.poll();
+ int index = (int) curr[1];
+ howManyLeft[index]++;
+ double diff = stations[index + 1] - stations[index];
+ double selectionLength = diff / (howManyLeft[index] + 1);
+ priorityQueue.add(new double[]{selectionLength, index});
+ }
+ return priorityQueue.peek()[0];
+ }
+
+ //Minimum possible answer: We will get the minimum answer when we place all the gas stations in a single location.
+ // Now, in this case, the maximum distance will be 0.
+ //Maximum possible answer: We will not place stations before the first or after the last station rather we will place stations in between the existing stations.
+ // So, the maximum possible answer is the maximum distance between two consecutive existing stations.
+ public double minimiseMaxDistance(int[] stations, int k) {
+ int n = stations.length; // size of the array
+ double left = 0;
+ double right = 0;
+
+ for (int i = 0; i < n - 1; i++) {
+ right = Math.max(right, stations[i + 1] - stations[i]);
+ }
+
+ double diff = 1e-6;
+
+ //The condition 'while(low <= high)' inside the 'while' loop won't work for decimal answers, and using it might lead to a TLE error.
+ // To avoid this, we can modify the condition to 'while(high - low > 10^(-6))'.
+ // This means we will only check numbers up to the 6th decimal place.
+ while (right - left < diff) {
+ double mid = (left + right) / (2.0);
+ int count = numberOfGasStationsRequired(stations, mid);
+ //low = mid+1: We have used this operation to eliminate the left half.
+ // But if we apply the same here, we might ignore several decimal numbers and possibly our actual answer.
+ // So, we will use this: low = mid.
+ if (count > k) {
+ //If result > k: On satisfying this condition, we can conclude that the number ‘mid’ is smaller than our answer.
+ // So, we will eliminate the left half and consider the right half
+ left = mid;
+ } else {
+ right = mid;
+ }
+ }
+ return right;
+ }
+
+ private int numberOfGasStationsRequired(int[] arr, double mid) {
+ int n = arr.length;
+ int cnt = 0;
+ for (int i = 1; i < n; i++) {
+ //For each section between i and i-1, we will do the following:
+ //No. of stations = (arr[i]-arr[i-1]) / dist
+ int numberInBetween = (int) ((arr[i] - arr[i - 1]) / mid);
+ //Let's keep in mind a crucial edge case: if the section_length (arr[i] - arr[i-1]) is completely divisible by 'dist',
+ // the actual number of stations required will be one less than what we calculate.
+ //if (arr[i]-arr[i-1] == (No. of stations*dist): No. of stations -= 1.
+ if ((arr[i] - arr[i - 1]) == (mid * numberInBetween)) {
+ numberInBetween--;
+ }
+ cnt += numberInBetween;
+ }
+ return cnt;
+ }
+}
diff --git a/src/main/java/binarysearch/MedianOfTwoSortedArrays.java b/src/main/java/binarysearch/MedianOfTwoSortedArrays.java
new file mode 100644
index 0000000..04b59d5
--- /dev/null
+++ b/src/main/java/binarysearch/MedianOfTwoSortedArrays.java
@@ -0,0 +1,137 @@
+package binarysearch;
+
+import java.util.Comparator;
+import java.util.PriorityQueue;
+
+/**
+ * https://www.youtube.com/watch?v=F9c7LpRZWVQ
+ * TODO revise
+ * tricky binary search
+ */
+public class MedianOfTwoSortedArrays {
+
+ public static void main(String[] args) {
+ int[] x = {1, 3, 8, 9, 15, 17, 30};
+ int[] y = {7, 11, 18, 19, 21, 25};
+ // 1,3,7,8,9,11,15,18,19,21,25
+ MedianOfTwoSortedArrays mm = new MedianOfTwoSortedArrays();
+ System.out.println(mm.findMedianSortedArraysEff(x, y) + " - " + mm.findMedianSortedArrays(x, y));
+ }
+
+ /**
+ * Each half contains (n/2) elements.
+ * Each half also contains x elements from the first array i.e. arr1[] and (n/2)-x elements from the second array i.e. arr2[].
+ * The value of x might be different for the two halves.
+ * For example, in the above array, the left half contains 3 elements from arr1[] and 2 elements from arr2[].
+ *
+ * @param input1
+ * @param input2
+ * @return
+ */
+ public double findMedianSortedArraysBruteForce(int[] input1, int[] input2) {
+ int[] merged = new int[input1.length + input2.length];
+ int i = 0;
+ int j = 0;
+ int k = 0;
+ while (i < input1.length && j < input2.length) {
+ if (input1[i] < input2[j]) {
+ merged[k++] = input1[i++];
+ } else {
+ merged[k++] = input2[j++];
+ }
+ }
+ while (i < input1.length) {
+ merged[k++] = input1[i++];
+ }
+ while (j < input2.length) {
+ merged[k++] = input2[j++];
+ }
+
+ if (merged.length % 2 == 0) {
+ return (merged[merged.length / 2] + merged[merged.length / 2 - 1]) / 2.0;
+ } else {
+ return merged[merged.length / 2];
+ }
+ }
+
+ public double findMedianSortedArrays(int[] input1, int[] input2) {
+ //if input1 length is greater than switch them so that input1 is smaller than input2.
+ // the reason is to do binary search on smaller array to reduce time complexity
+ if (input1.length > input2.length) {
+ return findMedianSortedArrays(input2, input1);
+ }
+ int x = input1.length;
+ int y = input2.length;
+ int n = x + y;
+ int leftHalf = (n + 1) / 2; // the reason is this works for both odd and even
+ // if the n is 10, 10+1/2 = median is 5, if n is 9, 9+1/2 = median 5
+
+ // the whole idea is to partition the 2 arrays so that the left side and right side have same number of elements
+ // let's take example A= 1,3,7 and B= 2,6,8,9,10
+
+ // first take (low + high) / 2 for A it'd be 1 in this example. we partition at 1, [1 ||, 3,7] (1 element on left and 2 on right)
+ // for B we need to do this, {(x + y + 1) / 2 - partitionX} = (3+5+1/2)-1=3 [2,6,8||,9,10] (3 elements on left and 2 on right)
+ // add the total left and right elements for both arrays would come to be equal 3+1(left partition) and 2+2(right partition)
+
+ int low = 0;
+ int high = x;
+ while (low <= high) {
+ int mid1 = (low + high) / 2;
+ int mid2 = leftHalf - mid1;
+
+ int left1 = (mid1 == 0) ? Integer.MIN_VALUE : input1[mid1 - 1];
+ int right1 = (mid1 == x) ? Integer.MAX_VALUE : input1[mid1];
+ int left2 = (mid2 == 0) ? Integer.MIN_VALUE : input2[mid2 - 1];
+ int right2 = (mid2 == y) ? Integer.MAX_VALUE : input2[mid2];
+
+ if (left1 <= right2 && left2 <= right1) {
+ if (n % 2 == 0) {
+ return (Math.max(left1, left2) + Math.min(right1, right2)) / 2.0;
+ } else {
+ return Math.max(left1, left2);
+ }
+ } else if (left1 > right2) {
+ //If l1 > r2: This implies that we have considered more elements from arr1[] than necessary.
+ // So, we have to take less elements from arr1[] and more from arr2[].
+ // In such a scenario, we should try smaller values of x.
+ // To achieve this, we will eliminate the right half (high = mid-1).
+ high = mid1 - 1;
+ }
+ //This implies that we have considered more elements from arr2[] than necessary.
+ // So, we have to take less elements from arr2[] and more from arr1[].
+ // In such a scenario, we should try bigger values of x.
+ // To achieve this, we will eliminate the left half (low = mid+1).
+ else low = mid1 + 1;
+
+ }
+ return -1.0;
+ }
+
+ public double findMedianSortedArraysEff(int[] nums1, int[] nums2) {
+
+ PriorityQueue minHeap = new PriorityQueue<>();
+ PriorityQueue maxHeap = new PriorityQueue<>(Comparator.reverseOrder());
+
+
+ for (int value : nums1) {
+ maxHeap.add(value);
+ }
+
+ for (int i : nums2) {
+ maxHeap.add(i);
+ }
+
+ int val = 0;
+ //division refers to integer division, this modified formula (n1+n2+1) / 2 will be valid for both cases of odd and even.
+ val = (nums1.length + nums2.length + 1) / 2;
+ for (int k = 0; k < val; k++) {
+ minHeap.add(maxHeap.poll());
+ }
+
+ if (minHeap.size() == maxHeap.size()) {
+ return (double) (minHeap.peek() + maxHeap.peek()) / 2;
+ } else {
+ return minHeap.peek();
+ }
+ }
+}
diff --git a/src/main/java/binarysearch/NumberOfDaysToMakeMBouquets.java b/src/main/java/binarysearch/NumberOfDaysToMakeMBouquets.java
new file mode 100644
index 0000000..6e4c4b0
--- /dev/null
+++ b/src/main/java/binarysearch/NumberOfDaysToMakeMBouquets.java
@@ -0,0 +1,48 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/minimum-number-of-days-to-make-m-bouquets/
+ */
+public class NumberOfDaysToMakeMBouquets {
+
+ public int minDays(int[] bloomDay, int m, int k) {
+ if ((long) m * k > bloomDay.length) {
+ return -1;
+ }
+
+ int left=1;
+ int right= Arrays.stream(bloomDay).max().orElse(0);
+
+ while(leftmid){ // if the day is greater, then break the window
+ window=0;
+ }else{
+ window++; // increase the window size
+ if(window==k){ // if the window size is equal to K end the window, we get one bouquet and reset the window for next
+ bouquets++;
+ window=0;
+ }
+ }
+ }
+ return bouquets>=m;
+ }
+}
diff --git a/src/main/java/binarysearch/NumberOfRectangles.java b/src/main/java/binarysearch/NumberOfRectangles.java
new file mode 100644
index 0000000..f8be65b
--- /dev/null
+++ b/src/main/java/binarysearch/NumberOfRectangles.java
@@ -0,0 +1,65 @@
+package binarysearch;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+
+/**
+ * https://leetcode.com/problems/count-number-of-rectangles-containing-each-point
+ * the constraints are
+ * 1 <= rectangles.length, points.length <= 5 * 10^4
+ * 1 <= li, xj <= 10^9
+ * 1 <= hi, yj <= 100
+ * This tells us that we cannot go through all the rectangles for all the points,
+ * coz that will be 5 * 10^4 * 5* 10^4 which would be > 10^8 operations, so would give TLE.
+ */
+public class NumberOfRectangles {
+ //We see that heights are only from 0 to 100.
+ // So can traverse in them. But lengths can be till 10^9 so have to do binary search in that.
+ public int[] countRectangles(int[][] rectangles, int[][] points) {
+ int[] res = new int[points.length];
+ List> group = new ArrayList<>(101);
+ for(int i = 0; i < 101; i++){
+ group.add(new ArrayList<>());
+ }
+
+ for(int[] rec : rectangles){
+ int l = rec[0];
+ int h = rec[1];
+ group.get(h).add(l);
+ }
+
+ for(int i = 0; i < 101; i++){
+ Collections.sort(group.get(i));
+ }
+
+ for(int i = 0; i < points.length; i++){
+ int count = 0;
+ int x = points[i][0];
+ int y = points[i][1];
+ for(int j = y; j < 101; j++){
+ List cur = group.get(j);
+ int index = binarySearch(cur, x);
+ count += cur.size() - index;
+ }
+ res[i] = count;
+ }
+
+ return res;
+ }
+
+ private int binarySearch(List list, int x){
+ int left = 0;
+ int right = list.size();
+ while(left < right){
+ int mid = left + (right - left) / 2;
+ if(list.get(mid) >= x){
+ right = mid;
+ } else{
+ left = mid + 1;
+ }
+ }
+ return left;
+ }
+}
diff --git a/src/main/java/binarysearch/PivotInteger.java b/src/main/java/binarysearch/PivotInteger.java
new file mode 100644
index 0000000..aec4bf0
--- /dev/null
+++ b/src/main/java/binarysearch/PivotInteger.java
@@ -0,0 +1,26 @@
+package binarysearch;
+
+public class PivotInteger {
+
+ public int pivotInteger(int n) {
+
+ int total = (n * (n + 1)) / 2;
+
+ int left = 0;
+ int right = n;
+
+ while (left < right) {
+ int mid = (left + right) / 2;
+
+ if ((mid * mid - total) < 0) {
+ left = mid + 1;
+ } else {
+ right = mid;
+ }
+
+ }
+
+ return left * left - total == 0 ? left : -1;
+
+ }
+}
diff --git a/src/main/java/binarysearch/SearchAnElementInMatrix.java b/src/main/java/binarysearch/SearchAnElementInMatrix.java
new file mode 100644
index 0000000..7c2f7e1
--- /dev/null
+++ b/src/main/java/binarysearch/SearchAnElementInMatrix.java
@@ -0,0 +1,87 @@
+package binarysearch;
+
+/**
+ * https://www.youtube.com/watch?v=FOa55B9Ikfg
+ * https://leetcode.com/problems/search-a-2d-matrix-ii/
+ * https://leetcode.com/problems/search-a-2d-matrix/
+ */
+
+public class SearchAnElementInMatrix {
+
+ private static boolean searchII(int[][] mat, int n, int x) {
+
+ int i = 0;
+ int j = n - 1; // set indexes for top right element
+ // we can start from top right corner or bottom left corner, because from
+ // these points only we have 2 paths one increasing one decreasing
+ // if we start at 0,0 both ways are increasing order, so we cannot decide
+ // same with n,n both ways are decreasing order.
+ while (i < n && j >= 0) {
+ if (mat[i][j] == x) {
+ System.out.print("n Found at " + i + " " + j);
+ return true;
+ }
+ if (mat[i][j] > x) {
+ j--;
+ } else // if mat[i][j] < x
+ {
+ i++;
+ }
+ }
+
+ System.out.print("n Element not found");
+ return false;
+
+ }
+
+ public static boolean searchI(int[][] matrix, int target) {
+ if (matrix == null || matrix.length == 0) {
+ return false;
+ }
+ int start = 0;
+ int rows = matrix.length;
+ int cols = matrix[0].length;
+ int end = rows * cols - 1;
+ while (start <= end) {
+ int mid = (start + end) / 2;
+ /**
+ * Row calculation (mid / col):
+ *
+ * Think of it as "how many complete rows do we need to move down?"
+ * Each row contains col number of elements
+ * Integer division gives us the number of complete rows
+ *
+ *
+ * Column calculation (mid % col):
+ *
+ * Think of it as "after moving down the rows, how many steps do we need to move right in the current row?"
+ * The modulus operation gives us the remainder, which is the offset within the current row
+ *
+ * Imagine a bookshelf with 5 shelves (rows), each holding 10 books (columns). If you're told to get the 37th book:
+ *
+ * You'd move down 3 full shelves (37 / 10 = 3)
+ * Then move 7 books to the right on the 4th shelf (37 % 10 = 7)
+ */
+ if (matrix[mid / cols][mid % cols] == target) {
+ return true;
+ }
+ if (matrix[mid / cols][mid % cols] < target) {
+ start = mid + 1;
+ } else {
+ end = mid - 1;
+ }
+ }
+ return false;
+ }
+
+ public static void main(String[] args) {
+ int[][] mat = {{10, 20, 30, 40}, {15, 25, 35, 45}, {27, 29, 37, 48}, {32, 33, 39, 50}};
+
+ int[][] matI = {{1, 3, 5, 7}, {10, 11, 16, 20}, {23, 30, 34, 50}};
+
+ System.out.println(searchI(matI, 11));
+ System.out.println(searchII(mat, 4, 33));
+
+ }
+
+}
diff --git a/src/main/java/binarysearch/SearchElementInSortedAndRotatedArray.java b/src/main/java/binarysearch/SearchElementInSortedAndRotatedArray.java
new file mode 100644
index 0000000..e65aa9c
--- /dev/null
+++ b/src/main/java/binarysearch/SearchElementInSortedAndRotatedArray.java
@@ -0,0 +1,76 @@
+package binarysearch;
+
+/**
+ * https://leetcode.com/problems/search-in-rotated-sorted-array/
+ * https://leetcode.com/problems/search-in-rotated-sorted-array-ii/
+ */
+public class SearchElementInSortedAndRotatedArray {
+
+ public static void main(String[] args) {
+ int[] arr = {4, 5, 6, 7, 0, 1, 2};
+
+ SearchElementInSortedAndRotatedArray search = new SearchElementInSortedAndRotatedArray();
+ System.out.println(search.searchI(arr, 0));
+
+ int[] nums = {2, 5, 6, 0, 0, 1, 2};
+ System.out.println(search.searchII(nums, 2));
+ }
+
+ // 4, 5, 0, 1, 2, 3
+ public int searchI(int[] nums, int target) {
+ int start = 0, end = nums.length - 1;
+ while (start <= end) {
+ int mid = start + (end - start) / 2;
+ if (nums[mid] == target) return mid;
+
+ else if (nums[mid] >= nums[start]) {
+ if (target >= nums[start] && target < nums[mid]) {
+ end = mid - 1;
+ }
+ else {
+ start = mid + 1;
+ }
+ }
+ else {
+ if (target <= nums[end] && target > nums[mid]) {
+ start = mid + 1;
+ }
+ else {
+ end = mid - 1;
+ }
+ }
+ }
+ return -1;
+ }
+
+ // with duplicates
+ //[2,5,6,0,0,1,2]
+ // 0
+ //duplicates, we know nums[mid] != target, so nums[start] != target //based on current information,
+ // we can only move left pointer to skip one cell
+ // thus in the worst case, we would have target: 2, and array like 11111111,
+ // then the running time would be O(n)
+
+ public boolean searchII(int[] nums, int target) {
+ int left = 0, right = nums.length - 1, mid;
+
+ while (left <= right) {
+ mid = (left + right) / 2;
+ if (nums[mid] == target) return true;
+
+ // the only difference from the first one, tricky case, just update left and right
+ if ((nums[left] == nums[mid]) && (nums[right] == nums[mid])) {
+ ++left;
+ --right;
+ } else if (nums[left] <= nums[mid]) {
+ if ((nums[left] <= target) && (nums[mid] > target)) right = mid - 1;
+ else left = mid + 1;
+ } else {
+ if ((nums[mid] < target) && (nums[right] >= target)) left = mid + 1;
+ else right = mid - 1;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/src/main/java/binarysearch/SearchInsertPosition.java b/src/main/java/binarysearch/SearchInsertPosition.java
new file mode 100644
index 0000000..0d68572
--- /dev/null
+++ b/src/main/java/binarysearch/SearchInsertPosition.java
@@ -0,0 +1,22 @@
+package binarysearch;
+
+/**
+ * https://leetcode.com/problems/search-insert-position/
+ */
+public class SearchInsertPosition {
+
+ public int searchInsert(int[] nums, int target) {
+ int left = 0;
+ //Also notice that the input target might be larger than all elements in nums and therefore needs to placed at the end of the array.
+ // That's why we should initialize right = len(nums) instead of right = len(nums) - 1.
+ int right = nums.length; // search space is [0, len] since insert index could be after last element
+
+ while (left < right) {
+ int mid = left + (right - left) / 2;
+ if (nums[mid] >= target) right = mid;
+ else left = mid + 1;
+ }
+
+ return left;
+ }
+}
diff --git a/src/main/java/binarysearch/ShipPackageWithNDays.java b/src/main/java/binarysearch/ShipPackageWithNDays.java
new file mode 100644
index 0000000..c905235
--- /dev/null
+++ b/src/main/java/binarysearch/ShipPackageWithNDays.java
@@ -0,0 +1,54 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/capacity-to-ship-packages-within-d-days
+ */
+public class ShipPackageWithNDays {
+ public static int shipWithinDays(int[] weights, int D) {
+ if (weights.length == 0 || D == 0) return 0;
+
+ // this is because the ship should carry atleast the max weight
+ // else the max would be rejected
+ int lowerBound = Arrays.stream(weights).max().orElse(0);
+ int upperBound = Arrays.stream(weights).sum();
+ int mid = 0;
+ while (lowerBound < upperBound) {
+ mid = (lowerBound + upperBound) / 2;
+ int daysToCarry = binarySearchUtil(weights, mid);
+ // if mid can carry weight then increase the upperBound to mid
+ if (daysToCarry<=D) upperBound = mid;
+ else lowerBound = mid + 1;
+
+ }
+
+ return lowerBound;
+ }
+
+
+ public static int binarySearchUtil(int[] weights, int mid) {
+ int sum = 0; // weight of current ship
+ int currentDay = 1; // number of days estimated
+ for (int weight : weights) {
+ if (sum + weight > mid) {
+ currentDay += 1;
+ sum = 0;
+
+ }
+ sum += weight;
+
+ // currentWeight += weight
+ //if (currentWeight > estimatedCapacity) {
+ // estimatedDays += 1 // current weight on the ship over estimated capacity so we need one more day
+ // currentWeight = weight // move the latest over weighted package to the ship on the following day
+ // }
+ }
+
+ return currentDay;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(shipWithinDays(new int[]{1,2,3,4,5,6,7,8,9,10}, 5));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/binarysearch/SingleElementInSortedArray.java b/src/main/java/binarysearch/SingleElementInSortedArray.java
new file mode 100644
index 0000000..26f5f00
--- /dev/null
+++ b/src/main/java/binarysearch/SingleElementInSortedArray.java
@@ -0,0 +1,38 @@
+package binarysearch;
+
+/**
+ * https://leetcode.com/problems/single-element-in-a-sorted-array
+ */
+public class SingleElementInSortedArray {
+
+ // the main idea here is the single element flips the order of the duplicates
+ // for example in [1,1,2,2,3,4,4,8,8] before 3 the order is (even,odd) after 3 the order is (odd,even)
+ public int singleNonDuplicate(int[] nums) {
+ if (nums.length == 1)
+ return nums[0];
+
+ int left = 1;
+ int right = nums.length - 1;
+ if(nums[0]!=nums[1]) return nums[0];
+ if(nums[nums.length-1]!=nums[nums.length-2]) return nums[nums.length-1];
+ while (left <= right) {
+ int mid = left + (right - left) / 2;
+ //base case
+ if (nums[mid - 1] != nums[mid] && nums[mid + 1] != nums[mid]) {
+ return nums[mid];
+ }
+ // if mid is odd and mid-1 is equal to mid then the single element is on the left
+ // if mid is even and mid+1 is equal to mid then the single element is on the left
+ //[1,1,2,2,3,4,4,8,8] here if the mid is odd say 3 we check the mid-1
+ // if the mid is even we check the mid+1 if the condition meets then we haven't
+ // seen the single element which flips the order of the duplicates
+ if((mid%2==1 && nums[mid] == nums[mid-1]) || (mid%2==0 && nums[mid]==nums[mid+1])){
+ left=mid+1;
+ }else{
+ right=mid-1;
+ }
+ }
+
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/binarysearch/SmallestDivisor.java b/src/main/java/binarysearch/SmallestDivisor.java
new file mode 100644
index 0000000..2b4e8b9
--- /dev/null
+++ b/src/main/java/binarysearch/SmallestDivisor.java
@@ -0,0 +1,33 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+// https://leetcode.com/problems/find-the-smallest-divisor-given-a-threshold/
+public class SmallestDivisor {
+
+ public int smallestDivisor(int[] nums, int threshold) {
+ int left=1;
+ int right= Arrays.stream(nums).max().orElse(0);
+
+ while(leftlimit){
+ partition++;
+ System.out.println("isFeasible limit is:: "+ limit +" "+ "but sum is " + sum + " so increasing partition "+partition);
+ sum=num;
+ }
+
+ }
+ System.out.println("End of isFeasible:: sum is "+ sum + " and partition is "+partition+" and m is "+m);
+ return partition<=m;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(new SubArraySplitSum().splitArray(new int[]{7,2,5,10,8}, 2));
+ //System.out.println(new SubArraySplitSum().splitArray(new int[]{1,4,4}, 3));
+ }
+}
diff --git a/src/main/java/binarysearch/SumMutatedArrayCloseTarget.java b/src/main/java/binarysearch/SumMutatedArrayCloseTarget.java
new file mode 100644
index 0000000..ce37e24
--- /dev/null
+++ b/src/main/java/binarysearch/SumMutatedArrayCloseTarget.java
@@ -0,0 +1,44 @@
+package binarysearch;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/sum-of-mutated-array-closest-to-target/
+ */
+public class SumMutatedArrayCloseTarget {
+ Integer closest = Integer.MAX_VALUE;
+ Integer minElem = 0;
+
+ public int findBestValue(int[] arr, int target) {
+ int left = 0;
+ int right = Arrays.stream(arr).max().orElse(0) + 1; // +1 is to extend the window slightly to overcome edge cases
+
+ while (left < right) {
+ int mid = left + (right - left) / 2;
+ if (isConditionSatisfies(mid, arr, target)) {
+ right = mid;
+ } else {
+ left = mid + 1;
+
+ }
+ }
+
+ return minElem;
+ }
+
+ public boolean isConditionSatisfies(int mid, int[] arr, int target) {
+ int total = 0;
+ for (int j : arr) {
+ total += Math.min(j, mid);
+
+ }
+ if (Math.abs(target - total) < closest) {
+ closest = Math.abs(target - total);
+ minElem = mid;
+ } else if (Math.abs(target - total) == closest) {
+ minElem = Math.min(minElem, mid);
+ }
+
+ return total >= target;
+ }
+}
diff --git a/src/main/java/bitwise/AddNumbers.java b/src/main/java/bitwise/AddNumbers.java
new file mode 100644
index 0000000..302057b
--- /dev/null
+++ b/src/main/java/bitwise/AddNumbers.java
@@ -0,0 +1,24 @@
+package bitwise;
+
+// https://leetcode.com/problems/add-binary/
+public class AddNumbers {
+ public String addBinary(String a, String b) {
+ StringBuilder sb = new StringBuilder();
+ int i = a.length()-1;
+ int j = b.length()-1;
+ int carry = 0;
+ while (i >= 0 || j >= 0 || carry == 1) {
+ if (i >= 0) {
+ carry += a.charAt(i--) - '0';
+ }
+ if (j >= 0) {
+ carry += b.charAt(j--) - '0';
+ }
+ sb.append(carry % 2);
+ carry /= 2;
+ }
+
+ return sb.reverse().toString();
+ }
+
+}
diff --git a/src/main/java/bitwise/BitwiseRange.java b/src/main/java/bitwise/BitwiseRange.java
new file mode 100644
index 0000000..e7aaef3
--- /dev/null
+++ b/src/main/java/bitwise/BitwiseRange.java
@@ -0,0 +1,31 @@
+package bitwise;
+
+// https://leetcode.com/problems/bitwise-and-of-numbers-range/
+public class BitwiseRange {
+
+
+ // https://www.youtube.com/watch?v=j3XRFREnPWI
+ // the reason here is there is a common prefix between the two numbers
+ // we find the common prefix and then shift it to the left
+ // this is a property of bitwise and
+
+ public static int rangeBitwiseAnd(int left, int right) {
+ int shift = 0;
+ System.out.println("le: " + Integer.toBinaryString(left));
+ System.out.println("ri: " + Integer.toBinaryString(right));
+ System.out.println("#########");
+ while (left < right) {
+ left >>= 1;
+ right >>= 1;
+ System.out.println("le : " + Integer.toBinaryString(left));
+ System.out.println("ri : " + Integer.toBinaryString(right));
+ shift++;
+ }
+
+ return left << shift;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(rangeBitwiseAnd(1024, 512));
+ }
+}
diff --git a/src/main/java/bitwise/ExcellentList.java b/src/main/java/bitwise/ExcellentList.java
new file mode 100644
index 0000000..b6d6308
--- /dev/null
+++ b/src/main/java/bitwise/ExcellentList.java
@@ -0,0 +1,51 @@
+package bitwise;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+// https://leetcode.com/problems/number-of-excellent-pairs/
+public class ExcellentList {
+ /**
+ https://leetcode.com/problems/number-of-excellent-pairs/solutions/2370663/c-logic-explained-with-pictures/
+ * If there are x set bits in a number and y set bits in b number
+ * then the OR component is x+y-k where k is the number of set bits common in a&b
+ * the AND component is k
+ * so the final answer (AND+OR) is x+y-k+k = x+y
+ * @param nums
+ * @param k
+ * @return
+ */
+ public long countExcellentPairs(int[] nums, int k) {
+ long[] count = new long[30]; // 30 instead of 32 because the constraint of the problem is
+ // 1E9 which can be considered as 2^30
+ Set set = Arrays.stream(nums).collect(HashSet::new, Set::add, Set::addAll);
+ for (int a: set){
+ count[Integer.bitCount(a)]++;
+ }
+ long result = 0L;
+ for (int i=1;i<30;++i){
+ for (int j=1;j<30;++j){
+ if (i+j >= k){
+ // the reason we are multiplying the count[i] and count[j] is because
+ // if we have 2 elements with i bits and 3 elements with j bits, then
+ // we can have 2*3 = 6 excellent pairs
+ /**
+ * Array: nums = [4, 6, 7, 10]
+ * k = 5
+ * Count Array:
+ * count[2] = 2 (two numbers with 2 1s: 4 and 6)
+ * count[3] = 1 (one number with 3 1s: 7)
+ * count[4] = 1 (one number with 4 1s: 10)
+ * Multiplication:
+ * count[2] * count[3] = 2 * 1 = 2 (pairs: (4, 7), (6, 7))
+ * count[2] * count[4] = 2 * 1 = 2 (pairs: (4, 10), (6, 10))
+ * Total potential excellent pairs: 4
+ */
+ result+=count[i]*count[j];
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/bitwise/MaxProductString.java b/src/main/java/bitwise/MaxProductString.java
new file mode 100644
index 0000000..fe0b165
--- /dev/null
+++ b/src/main/java/bitwise/MaxProductString.java
@@ -0,0 +1,48 @@
+package bitwise;
+
+public class MaxProductString {
+
+ public int maxProduct(String[] words) {
+ int[] checker = new int[words.length];
+ int max = 0;
+ // populating the checker array with their respective numbers
+ for (int i = 0; i < checker.length; i++) {
+ int num = 0;
+ for (int j = 0; j < words[i].length(); j++) {
+
+ // a 1->1
+ // b 2->10
+ // c 4->100
+ // ab 3->11
+ // ac 5->101
+ // abc 7->111
+ // az 33554433->10000000000000000000000001
+
+ num |= 1 << (words[i].charAt(j) - 'a');
+ //System.out.println(words[i].charAt(j)+"->"+num+ "->"+Integer.toBinaryString(num) );
+ }
+
+ checker[i] = num;
+ }
+
+ for (int i = 0; i < words.length; i++) {
+ for (int j = i + 1; j < words.length; j++) {
+ // bitwise and operation between two numbers
+ // if the result is 0, then there is no common character
+ // if the result is not 0, then there is a common character
+ if ((checker[i] & checker[j]) == 0)
+ max = Math.max(max, words[i].length() * words[j].length());
+ }
+ }
+ System.out.println(max);
+ return max;
+ }
+
+
+ public static void main(String[] args) {
+ MaxProductString m = new MaxProductString();
+ m.maxProduct(new String[]{"abcw", "baz", "foo", "bar", "xtfn", "abcdef"});
+ m.maxProduct(new String[]{"a", "ab", "abc", "d", "cd", "bcd", "abcd"});
+ m.maxProduct(new String[]{"a", "aa", "aaa", "aaaa"});
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/bitwise/Reverse.java b/src/main/java/bitwise/Reverse.java
new file mode 100644
index 0000000..6097f1f
--- /dev/null
+++ b/src/main/java/bitwise/Reverse.java
@@ -0,0 +1,14 @@
+package bitwise;
+
+// https://leetcode.com/problems/reverse-bits/
+public class Reverse {
+
+ public int reverseBits(int n) {
+ int ans =0;
+ for(int i=0;i<=31;i++){
+ int bit = n>>i & 1;
+ ans|=(bit<<31-i);
+ }
+ return ans;
+ }
+}
diff --git a/src/main/java/bitwise/SingleNumberII.java b/src/main/java/bitwise/SingleNumberII.java
new file mode 100644
index 0000000..b2da3d4
--- /dev/null
+++ b/src/main/java/bitwise/SingleNumberII.java
@@ -0,0 +1,70 @@
+package bitwise;
+// https://leetcode.com/problems/single-number-ii/
+// https://leetcode.com/problems/single-number-iii/
+public class SingleNumberII {
+ public int singleNumber(int[] nums) {
+ int ans = 0;
+
+ for (int i = 0; i < 32; ++i) {
+ int sum = 0;
+ for (final int num : nums) {
+ // This step creates a bitmask pos where only the bit at
+ // position i is set to the value of sum
+ sum += num >> i & 1;
+ }
+ //Take the modulo of sum by 3: sum %= 3
+ // This will clear the ith bit of ans if the corresponding bit of sum is 3.
+ // It will leave it as 1 if the corresponding bit of sum is 1.
+ sum %= 3;
+
+ //Use the bitwise OR operation with ans and pos: ans |= pos.
+ // This sets the corresponding bit in ans to 1
+ // if the bit at position i is part of an unbalanced line.
+ ans |= sum << i;
+ }
+
+ return ans;
+ }
+
+ /**
+ * High level: find XOR combo of two result. Then find one of them
+ * Step 1: XOR all numbers, the result will be res1 ^ res2
+ * Step 2: traverse all 32 bit indexes of previous XOR result, once we find there exist 1 on a bit index, break
+ * the loop. Because one of the result at least have bit 1 on current bit index
+ * Step 3: traverse all numbers in the input array, if we find a number & the bit index we found at step 2 is not 0,
+ * then we can use res1 XOR current num to iteratively fill out effective bit in res1
+ * (i.e. res1 ^ n1 ^ n1 ^ n2 ^ n2 = res1, if res1, n1 and n2 have bit 1 on the bitIndex
+ * Step 4: find another result number by using res1 ^ allNumberXOR (i.e. res1 ^ (res1 ^ res2 ^ ...)) = res2)
+ * */
+
+ public int[] singleNumberIII(int[] nums) {
+ int res1 = 0;
+ int res2 = 0;
+
+ // step 1: find XOR combo of two numbers
+ int allNumXOR = 0;
+ for (int num : nums) {
+ allNumXOR ^= num;
+ }
+
+ // step 2: find effective bit index of a number in one of two result numbers
+ int bitIndex;
+ for (bitIndex = 0; bitIndex < 32; bitIndex++) {
+ if ((allNumXOR & (1 << bitIndex)) != 0) {
+ break;
+ }
+ }
+
+ // step 3: find first result
+ for (int num : nums) {
+ if ((num & (1 << bitIndex)) != 0) {
+ // current bitIndex, we only want that single one,
+ // and cancel all the rest of numbers by using XOR
+ res1 ^= num;
+ }else{
+ res2 ^= num;
+ }
+ }
+ return new int[]{res1, res2};
+ }
+}
diff --git a/src/main/java/bitwise/Subset.java b/src/main/java/bitwise/Subset.java
new file mode 100644
index 0000000..aa2519c
--- /dev/null
+++ b/src/main/java/bitwise/Subset.java
@@ -0,0 +1,34 @@
+package bitwise;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Subset {
+
+ public List> subsets(int[] nums) {
+ List> result = new ArrayList<>();
+ int n=nums.length;
+ /*
+
+ Iteration 1: num = 0 (000 in binary), loop skips.
+ Iteration 2: num = 1 (001), subset = [1].
+ Iteration 3: num = 2 (010), subset = [2].
+ Iteration 4: num = 3 (011), subset = [1, 3].
+ Iteration 5: num = 4 (100), subset = [3].
+ Iteration 6: num = 5 (101), subset = [2, 3].
+ Iteration 7: num = 6 (110), subset = [1, 2].
+ Iteration 8: num = 7 (111), subset = [1, 2, 3].
+ */
+ for (int i = 0; i < (1 << n); i++) {
+ ArrayList in = new ArrayList<>();
+ for (int j = 0; j < n; j++) {
+ if ((i & (1 << j)) != 0) {
+ in.add(nums[j]);
+ }
+ }
+ result.add(in);
+ }
+
+ return result; // total complexity: n.2^n
+ }
+}
diff --git a/src/main/java/cess/AppleDivision.java b/src/main/java/cess/AppleDivision.java
new file mode 100644
index 0000000..ce81c69
--- /dev/null
+++ b/src/main/java/cess/AppleDivision.java
@@ -0,0 +1,31 @@
+package cess;
+
+/**
+ * Bitmask
+ *
+ * https://cses.fi/problemset/task/1623
+ * https://www.youtube.com/watch?v=raGn3saVfa8
+ */
+public class AppleDivision {
+
+ public static long solve(int[] arr) {
+ long result = Long.MAX_VALUE;
+ int n = arr.length;
+ for (int mask = 0; mask < (1 << n); mask++) {
+
+ long sumA = 0;
+ long sumB = 0;
+
+ for (int pos = 0; pos < n; pos++) {
+ if ((mask & (1 << pos)) > 0) {
+ sumA += arr[pos];
+ } else {
+ sumB += arr[pos];
+ }
+ }
+ result = Math.min(result, Math.abs(sumA - sumB));
+
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/cess/BinaryExponentiation.java b/src/main/java/cess/BinaryExponentiation.java
new file mode 100644
index 0000000..eea8ba6
--- /dev/null
+++ b/src/main/java/cess/BinaryExponentiation.java
@@ -0,0 +1,20 @@
+package cess;
+
+public class BinaryExponentiation {
+
+ /**
+ * Fast method to compute exponent values a^b
+ * https://www.youtube.com/watch?v=L-Wzglnm4dM
+ */
+ public int power(int a, int b) {
+
+ int result = 1;
+
+ while (b > 0) {
+ if (b == 1) result *= a;
+ a *= a;
+ b /= 2;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/cess/DigitQueries.java b/src/main/java/cess/DigitQueries.java
new file mode 100644
index 0000000..afe8745
--- /dev/null
+++ b/src/main/java/cess/DigitQueries.java
@@ -0,0 +1,67 @@
+package cess;
+
+import java.util.Arrays;
+
+/**
+ * https://www.youtube.com/watch?v=QAcH8qD9Pe0
+ * https://cses.fi/problemset/task/2431
+ *
+ * too complex, debug to understand
+ */
+public class DigitQueries {
+
+ public static String solve(long[] arr) {
+ long[] powerOfTen = new long[19];
+ Arrays.fill(powerOfTen, 1);
+
+ for (int i = 1; i < powerOfTen.length; i++) {
+ powerOfTen[i] = powerOfTen[i - 1] * 10;
+
+ }
+
+ for (long index : arr) {
+
+ long digitsSoFar = 0;
+ long digitsBeforeActualBlock = 0;
+ int numberOfDigits = 0;
+
+ for (int j = 1; j <= 18; j++) {
+ long distance = (powerOfTen[j] * powerOfTen[j - 1]) * j;
+
+ digitsSoFar += distance;
+
+ if (digitsSoFar >= index) {
+ numberOfDigits = j;
+ break;
+ }
+ digitsBeforeActualBlock += distance;
+ }
+
+ long smallestValue = powerOfTen[numberOfDigits - 1];
+ long largestValue = powerOfTen[numberOfDigits] - 1;
+ long bestValue = 0;
+ long bestValueStartPos = 0;
+
+ while (smallestValue <= largestValue) {
+ long mid = (smallestValue + largestValue) / 2;
+ long startPostOfActual = digitsBeforeActualBlock + 1 + (mid - powerOfTen[numberOfDigits - 1]) * numberOfDigits;
+ if (startPostOfActual <= index) {
+ if (mid > bestValue) {
+ bestValue = mid;
+ bestValueStartPos = startPostOfActual;
+ }
+ smallestValue = mid + 1;
+ } else {
+ largestValue = mid - 1;
+ }
+ }
+ int res = (int) ((int) index - bestValueStartPos);
+ return String.valueOf(String.valueOf(bestValue).charAt(res));
+ }
+ return "";
+ }
+
+ public static void main(String[] args) {
+ solve(new long[]{107});
+ }
+}
diff --git a/src/main/java/cess/GreyCode.java b/src/main/java/cess/GreyCode.java
new file mode 100644
index 0000000..9e2a04b
--- /dev/null
+++ b/src/main/java/cess/GreyCode.java
@@ -0,0 +1,70 @@
+package cess;
+
+
+import java.util.ArrayList;
+import java.util.BitSet;
+import java.util.List;
+
+/**
+ * https://www.youtube.com/watch?v=KOD2BFauQbA
+ * A Gray code is a list of all 2n
+ * bit strings of length n
+ * , where any two successive strings differ in exactly one bit (i.e., their Hamming distance is one).
+ * Your task is to create a Gray code for a given length n
+ *
+ *
+ * Input:
+ * 2
+ *
+ * Output:
+ * 00 -|
+ * 01 -| - difference 1
+ * 11
+ * 10
+ */
+public class GreyCode {
+
+ public static List greyCode(int n) {
+
+ if (n == 0) return new ArrayList<>();
+ if (n == 1) {
+ List baseRes = new ArrayList<>();
+ baseRes.add("0");
+ baseRes.add("1");
+ return baseRes;
+ }
+
+ List intermediateResult = greyCode(n - 1);
+ List finalResult = new ArrayList<>();
+ for (String s : intermediateResult) {
+ finalResult.add("0" + s);
+ }
+
+ for (int i = intermediateResult.size() - 1; i >= 0; i--) {
+ finalResult.add("1" + intermediateResult.get(i));
+ }
+ return finalResult;
+
+ }
+
+ public static List greyCode1(int n) {
+ List finalResult = new ArrayList<>();
+ for (int i = 0; i < 1 << n; i++) {
+ int val = i ^ (i >> 1);
+
+ // If len = 4 and val = 1,
+ // Integer.toBinaryString( (1 << len) | val ) => returns the string "10001", then
+ // "10001".substring( 1 ) discards the very first character. So we obtain what we want:
+ // "0001"
+ finalResult.add(Integer.toBinaryString((1 << n) | val).substring(1));
+ }
+ return finalResult;
+ }
+
+ public static void main(String[] args) {
+ BitSet b = new BitSet();
+ greyCode(3).forEach(System.out::println);
+ System.out.println();
+ greyCode1(3).forEach(System.out::println);
+ }
+}
diff --git a/src/main/java/cess/GridPath.java b/src/main/java/cess/GridPath.java
new file mode 100644
index 0000000..dab0fb4
--- /dev/null
+++ b/src/main/java/cess/GridPath.java
@@ -0,0 +1,153 @@
+package cess;
+
+public class GridPath {
+
+ public static boolean[][] onPath = new boolean[9][9];
+ public static int[][] dirs = new int[][]{{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
+ static int[] p = new int[48];
+
+ /**
+ * Basic Algorithm
+
+ * The first version of the algorithm does not contain any optimizations. We simply
+ * use backtracking to generate all possible paths from the upper-left corner to
+ * the lower-right corner and count the number of such paths.
+
+ * Running time: 483 seconds
+ * Number of recursive calls: 76 billion
+ *
+ *
+ * Optimization 1
+ *
+ * If the path reaches the lower-right square before it has visited all other
+ * squares of the grid, it is clear that it will not be possible to complete the
+ * solution. Using this observation, we can terminate the search immediately if we
+ * reach the lower-right square too early.
+ *
+ * Running time: 119 seconds
+ * Number of recursive calls: 20 billion
+ *
+ *
+ * If the path touches a wall and can turn either left or right, the grid splits
+ * into two parts that contain unvisited squares. In this case, we cannot visit all
+ * squares anymore, so we can terminate the search.
+ *
+ * Running time: 1.8 seconds
+ * Number of recursive calls: 221 million
+ *
+ *
+ * The idea of Optimization 2 can be generalized: if the path cannot continue
+ * forward but can turn either left or right, the grid splits into two parts that
+ * both contain unvisited squares. It is clear that we cannot visit all squares
+ * anymore, so we can terminate the search.
+ *
+ * Running time: 0.6 seconds
+ * Number of recursive calls: 69 million
+ *
+ *
+ * Now is a good moment to stop optimizing the algorithm and see what we have
+ * achieved. The running time of the original algorithm was $483$ seconds, and now
+ * after the optimizations, the running time is only $0.6$ seconds. Thus, the
+ * algorithm became nearly $1000$ times faster after the optimizations.
+ *
+ * Optimization 4
+ *
+ * If the path creates a dead end that is not the bottom left corner, either the
+ * path will fail to visit all squares (the path may stop at the dead end or pass
+ * over it, sealing a square off) or the path will end in the wrong location. Thus,
+ * we want to avoid creating dead ends. For example, if the square to the left of
+ * our current location is blocked on three sides (including our current location),
+ * then the next step must be to the left in order to avoid creating a dead end.
+ * After this optimization, the program runs in under $1$ second.
+ */
+ public int calculateGridPaths(String line) {
+ if (line.length() != 48) return -1;
+
+ for (int i = 0; i < p.length; i++) {
+ char cur = line.charAt(i);
+
+ if (cur == 'U') p[i] = 0;
+ else if (cur == 'R') p[i] = 1;
+ else if (cur == 'D') p[i] = 2;
+ else if (cur == 'L') p[i] = 3;
+ else p[i] = 4; // cur == '?'
+ }
+
+ // set borders of grid
+ for (int i = 0; i < 9; i++) {
+ onPath[0][i] = true;
+ onPath[8][i] = true;
+ onPath[i][0] = true;
+ onPath[i][8] = true;
+ }
+
+ return tryPath(0, 1, 1);
+ }
+
+ public static int tryPath(int pathIdx, int curR, int curC) {
+ // Optimization 3
+ if ((onPath[curR][curC - 1] && onPath[curR][curC + 1]) &&
+ (!onPath[curR - 1][curC] && !onPath[curR + 1][curC]))
+ return 0;
+ if ((onPath[curR - 1][curC] && onPath[curR + 1][curC]) &&
+ (!onPath[curR][curC - 1] && !onPath[curR][curC + 1]))
+ return 0;
+
+ // Optimization 1
+ if (curR == 7 && curC == 1) { // reached endpoint
+ if (pathIdx == p.length) return 1; // visited every cell -> valid!
+ return 0; // didn't visit every cell (path length is too short)
+ }
+ // visited all cells, but didn't end up in the correct location
+ if (pathIdx == p.length) return 0;
+
+ int ret = 0; // cumulative count for this "starting position"
+ onPath[curR][curC] = true;
+
+ // turn already determined, try going in that direction
+ if (p[pathIdx] < 4) {
+ int nxtR = curR + dirs[p[pathIdx]][0];
+ int nxtC = curC + dirs[p[pathIdx]][1];
+ if (!onPath[nxtR][nxtC]) {
+ ret += tryPath(pathIdx + 1, nxtR, nxtC);
+ }
+ }
+// // now search for dead ends (Optimization 4)
+// else if ((curC > 2) && onPath[curR][curC - 2] &&
+// (onPath[curR - 1][curC - 1] || onPath[curR + 1][curC - 1]) &&
+// (!onPath[curR][curC - 1])) {
+// // potential dead end on the left:
+// int nxtR = curR;
+// int nxtC = curC - 1;
+// ret += tryPath(pathIdx + 1, nxtR, nxtC);
+// } else if ((curC < 6) && onPath[curR][curC + 2] &&
+// (onPath[curR - 1][curC + 1] || onPath[curR + 1][curC + 1]) &&
+// (!onPath[curR][curC + 1])) {
+// // potential dead end on the right:
+// int nxtR = curR;
+// int nxtC = curC + 1;
+// ret += tryPath(pathIdx + 1, nxtR, nxtC);
+// } else if ((curR > 2) && onPath[curR - 2][curC] &&
+// onPath[curR - 1][curC - 1] && (!onPath[curR - 1][curC])) {
+// // potential dead end upwards
+// // note: I didn't include all possible scenarios because
+// // it wasn't necessary in order for the program to run in time
+// int nxtR = curR - 1;
+// int nxtC = curC;
+// ret += tryPath(pathIdx + 1, nxtR, nxtC);
+// }
+ // iterate through all four possible turns
+ else {
+ for (int i = 0; i < 4; i++) {
+ int nxtR = curR + dirs[i][0];
+ int nxtC = curC + dirs[i][1];
+ if (onPath[nxtR][nxtC]) continue;
+ ret += tryPath(pathIdx + 1, nxtR, nxtC);
+ }
+ }
+
+ // reset and return
+ onPath[curR][curC] = false;
+ return ret;
+ }
+}
diff --git a/src/main/java/cess/NumberFromSpiral.java b/src/main/java/cess/NumberFromSpiral.java
new file mode 100644
index 0000000..6829749
--- /dev/null
+++ b/src/main/java/cess/NumberFromSpiral.java
@@ -0,0 +1,39 @@
+package cess;
+
+/**
+ * https://cses.fi/problemset/task/1071
+ * https://www.youtube.com/watch?v=pNN35ZdX77Y
+ *
+ * tricky complex
+ */
+public class NumberFromSpiral {
+
+ public int getValueAtIndex(int i, int j) {
+
+ int max = Math.max(i, j);
+
+ if ((max & 1) == 0) {
+ if (j == 1) {
+ return max * max;
+ }
+
+ if (i < max) {
+ return getValueAtIndex(max, max) - (max - i);
+ } else if (i == max) {
+ return max * max - (j - 1);
+ }
+ } else {
+ if (i == 1) {
+ return max * max;
+ }
+
+ if (j < max) {
+ return getValueAtIndex(max, max) - (max - j);
+ } else {
+ return max * max - (i - 1);
+ }
+ }
+ return -1;
+ }
+
+}
diff --git a/src/main/java/cess/PalindromeReorder.java b/src/main/java/cess/PalindromeReorder.java
new file mode 100644
index 0000000..ab3b984
--- /dev/null
+++ b/src/main/java/cess/PalindromeReorder.java
@@ -0,0 +1,49 @@
+package cess;
+
+/**
+ * https://cses.fi/problemset/task/1755
+ * https://www.youtube.com/watch?v=ou8Xhp_YO8E&t=767s
+ */
+public class PalindromeReorder {
+
+ public static String reorderToPalindrome(String s) {
+
+ int[] arr = new int[26];
+
+ for (char c : s.toCharArray()) {
+ arr[c - 'A']++;
+ }
+
+ int oddCharPos = -1;
+
+ for (int i = 0; i < 26; i++) {
+ if (arr[i] == 1 && oddCharPos != -1) {
+ return "";
+ } else if (arr[i] == 1 && oddCharPos == -1) {
+ oddCharPos = i;
+ }
+ }
+
+ if (oddCharPos == -1 && s.length() % 2 == 1) return "";
+ if (oddCharPos != -1 && s.length() % 2 == 0) return "";
+
+ StringBuilder sb = new StringBuilder();
+
+ for (int i = 0; i < 26; i++) {
+ for (int j = 0; j < arr[i] / 2; j++) {
+ sb.append(Character.toString(i + 'A'));
+ }
+ }
+
+ String s1 = sb.reverse().toString();
+ sb.reverse();
+ if (oddCharPos != -1) {
+ sb.append(Character.toString(oddCharPos + 'A'));
+ }
+ return sb.append(s1).toString();
+ }
+
+ public static void main(String[] args) {
+ System.out.println(reorderToPalindrome("AAAACACBA"));
+ }
+}
diff --git a/src/main/java/cess/TowerOfHanoi.java b/src/main/java/cess/TowerOfHanoi.java
new file mode 100644
index 0000000..5bbf0fa
--- /dev/null
+++ b/src/main/java/cess/TowerOfHanoi.java
@@ -0,0 +1,20 @@
+package cess;
+
+public class TowerOfHanoi {
+
+ public static void solve(String from, String to, String aux, int n) {
+ if (n == 1) {
+ System.out.println("Take disk 1 from rod " + from + " to rod " + to);
+ return;
+ }
+ solve(from, aux, to, n - 1);
+ System.out.println("Take disk " + n + " from rod " + from + " to rod " + to);
+
+ System.out.println();
+ solve(aux, to, from, n - 1);
+ }
+
+ public static void main(String[] args) {
+ solve("A", "C", "B", 3);
+ }
+}
diff --git a/src/main/java/cess/TwoKnights.java b/src/main/java/cess/TwoKnights.java
new file mode 100644
index 0000000..1eba0b7
--- /dev/null
+++ b/src/main/java/cess/TwoKnights.java
@@ -0,0 +1,22 @@
+package cess;
+
+/**
+ * https://cses.fi/problemset/task/1072
+ *
+ * https://www.youtube.com/watch?v=nKVubpav6Uk
+ */
+public class TwoKnights {
+
+ public int getNumberOfWays(int n) {
+
+ // number af all possibilities to place 2 knights on n*n board
+ // binomial formula
+ int numberOfAllPossibilities = (((n * n) * (n * n) - 1) / 2);
+
+ //number Of rectangles Where two knights can attack each other
+ int noOfRect = 4 * (n - 1) * (n - 2);
+
+ // this return no of ways the two knights cannot attack each other
+ return numberOfAllPossibilities - noOfRect;
+ }
+}
diff --git a/src/main/java/cess/sort_search/Apartments.java b/src/main/java/cess/sort_search/Apartments.java
new file mode 100644
index 0000000..ffae1ec
--- /dev/null
+++ b/src/main/java/cess/sort_search/Apartments.java
@@ -0,0 +1,33 @@
+package cess.sort_search;
+
+import java.util.Arrays;
+
+public class Apartments {
+
+ public static int search(int[] memberReq, int[] apartments, int diff) {
+ Arrays.sort(apartments);
+ Arrays.sort(memberReq);
+ int i = 0;
+ int j = 0;
+ int ans = 0;
+ for (; i < memberReq.length; i++) {
+ // if the curr space is less, then try finding a suitable apartment for applicant i
+ while (j < apartments.length && apartments[j] < memberReq[i] - diff) {
+ j++;
+ }
+ if (Math.abs(apartments[j] - memberReq[i]) <= diff) {
+ ans++;
+ i++;
+ j++;
+ } else {
+ // if it's large then move to next applicant
+ i++;
+ }
+ }
+ return ans;
+ }
+
+ public static void main(String[] args) {
+ search(new int[]{60,45,80,60},new int[]{30,60,75}, 5);
+ }
+}
diff --git a/src/main/java/cess/sort_search/MovieFestival.java b/src/main/java/cess/sort_search/MovieFestival.java
new file mode 100644
index 0000000..e3d4cfc
--- /dev/null
+++ b/src/main/java/cess/sort_search/MovieFestival.java
@@ -0,0 +1,41 @@
+package cess.sort_search;
+
+import graph.leetcode.Pair;
+
+import java.util.*;
+
+// similar to intervals problem but with a twist
+public class MovieFestival {
+
+ public static int moviesWatchedCount(int[][] movieTimings, int persons){
+ int unWatchableCount = 0;
+ Arrays.sort(movieTimings, Comparator.comparingInt(a -> a[1]));
+ TreeSet> set = new TreeSet<>(Comparator.comparingInt(a -> a.key));
+
+ for(int i=0;i(movieTimings[i][1]*-1,i));
+ continue;
+ }
+ Pair p = set.lower(new Pair<>(movieTimings[i][0]*-1,-1));
+ if (p!=null && !Objects.equals(p.value, set.last().value)){
+ set.remove(p);
+ set.add(new Pair<>(movieTimings[i][1]*-1,i));
+ continue;
+ }
+ if (set.size() < persons){
+ set.add(new Pair<>(movieTimings[i][1]*-1,i));
+ }else {
+ unWatchableCount++;
+ }
+
+ }
+
+ return movieTimings.length - unWatchableCount;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(moviesWatchedCount(new int[][]{{1,5},{8,10},{3,6},{2,5},{6,9}},2));
+ }
+
+}
diff --git a/src/main/java/cess/sort_search/RestaurantCustomers.java b/src/main/java/cess/sort_search/RestaurantCustomers.java
new file mode 100644
index 0000000..bb8e8d3
--- /dev/null
+++ b/src/main/java/cess/sort_search/RestaurantCustomers.java
@@ -0,0 +1,29 @@
+package cess.sort_search;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * https://cses.fi/problemset/task/1619
+ * https://www.youtube.com/watch?v=O9Sptr-RdRo
+ */
+public class RestaurantCustomers {
+
+ public int maxCustomersAtGivenTime(int[][] arrivalTimes){
+ Map cache = new TreeMap<>();
+
+ for (int[] arr:arrivalTimes) {
+ cache.put(arr[0],1);
+ cache.put(arr[1],-1);
+ }
+ int ans =0;
+ int count =0;
+ for (Map.Entry entry : cache.entrySet()){
+
+ ans = Math.max(ans,count+entry.getValue());
+ }
+
+ return ans;
+
+ }
+}
diff --git a/src/main/java/cess/sort_search/SubsetSumCoin.java b/src/main/java/cess/sort_search/SubsetSumCoin.java
new file mode 100644
index 0000000..1578ec5
--- /dev/null
+++ b/src/main/java/cess/sort_search/SubsetSumCoin.java
@@ -0,0 +1,31 @@
+package cess.sort_search;
+
+import java.util.Arrays;
+
+public class SubsetSumCoin {
+
+ public static int sumCannotFormedBySubset(int[] arr) {
+ int res = 1; // Initialize result
+
+ // sort the input array
+ Arrays.sort(arr);
+
+ // Traverse the array and increment 'res' if arr[i] is
+ // smaller than or equal to 'res'.
+ for (int i = 0; i < arr.length; i++)
+ {
+ if(arr[i] > res){
+ return res;
+ }
+ else{
+ res+=arr[i];
+ }
+ }
+
+ return res;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(sumCannotFormedBySubset(new int[]{2,9,1,2,7}));
+ }
+}
diff --git a/src/main/java/combinationsandpermutations/BeautifulArrangements.java b/src/main/java/combinationsandpermutations/BeautifulArrangements.java
new file mode 100644
index 0000000..34cb4ea
--- /dev/null
+++ b/src/main/java/combinationsandpermutations/BeautifulArrangements.java
@@ -0,0 +1,26 @@
+package combinationsandpermutations;
+
+/**
+ * https://leetcode.com/problems/beautiful-arrangement
+ */
+public class BeautifulArrangements {
+ public int countArrangement(int n) {
+ boolean[] visited = new boolean[n + 1];
+ return count(visited, n, n);
+ }
+
+ private int count(boolean[] visited, int index, int n) {
+ if (index == 0) {
+ return 1;
+ }
+ int count = 0;
+ for (int i = 1; i <= n; i++) {
+ if ((index % i == 0 || i % index == 0) && !visited[i]) {
+ visited[i] = true;
+ count += count(visited, index - 1, n);
+ visited[i] = false;
+ }
+ }
+ return count;
+ }
+}
diff --git a/src/main/java/combinationsandpermutations/CanPartitionKSubSets.java b/src/main/java/combinationsandpermutations/CanPartitionKSubSets.java
new file mode 100644
index 0000000..8f49efa
--- /dev/null
+++ b/src/main/java/combinationsandpermutations/CanPartitionKSubSets.java
@@ -0,0 +1,37 @@
+package combinationsandpermutations;
+
+import java.util.Arrays;
+
+/**
+ * Tricky TODO revise
+ * https://leetcode.com/problems/partition-to-k-equal-sum-subsets/
+ *
+ * Ref: http://www.geeksforgeeks.org/partition-set-k-subsets-equal-sum/
+ */
+public class CanPartitionKSubSets {
+ public boolean canPartitionKSubsets(int[] A, int k) {
+ if (k > A.length) return false;
+ int sum = 0;
+ for (int num : A) sum += num;
+ if (sum % k != 0) return false;
+ boolean[] visited = new boolean[A.length];
+ Arrays.sort(A);
+ return dfs(A, 0, A.length - 1, visited, sum / k, k);
+ }
+
+ public boolean dfs(int[] A, int sum, int st, boolean[] visited, int target, int round) {
+ if (round == 0) return true;
+
+ if (sum == target && dfs(A, 0, A.length - 1, visited, target, round - 1))
+ return true;
+ for (int i = st; i >= 0; --i) {
+ if (!visited[i] && sum + A[i] <= target) {
+ visited[i] = true;
+ if (dfs(A, sum + A[i], i - 1, visited, target, round))
+ return true;
+ visited[i] = false;
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/combinationsandpermutations/CombinationIterator.java b/src/main/java/combinationsandpermutations/CombinationIterator.java
new file mode 100644
index 0000000..352b1c8
--- /dev/null
+++ b/src/main/java/combinationsandpermutations/CombinationIterator.java
@@ -0,0 +1,54 @@
+package combinationsandpermutations;
+
+// CombinationIterator iterator = new CombinationIterator("abc", 2); // creates the iterator.
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+// iterator.next(); // returns "ab"
+// iterator.hasNext(); // returns true
+// iterator.next(); // returns "ac"
+// iterator.hasNext(); // returns true
+// iterator.next(); // returns "bc"
+// iterator.hasNext(); // returns false
+public class CombinationIterator {
+ Deque deque;
+ boolean[] visited;
+
+ public CombinationIterator(String characters, int combinationLength) {
+ deque = new ArrayDeque<>();
+ visited = new boolean[characters.length()];
+ generateCombinations(characters, deque, new StringBuilder(), combinationLength, 0);
+ }
+
+ public String next() {
+ if (hasNext()) return deque.poll();
+
+ return "";
+ }
+
+ public boolean hasNext() {
+ return !deque.isEmpty();
+ }
+
+ public void generateCombinations(String characters, Deque deque, StringBuilder sb, int limit, int start) {
+
+ if (sb.length() == limit) {
+ deque.offer(sb.toString());
+ return;
+ }
+
+ for (int i = start; i < characters.length(); i++) {
+ sb.append(characters.charAt(i));
+ generateCombinations(characters, deque, sb, limit, i + 1);
+ sb.deleteCharAt(sb.length() - 1);
+ }
+ }
+
+ public static void main(String[] args) {
+ CombinationIterator cb = new CombinationIterator("abc", 2);
+ System.out.println(cb.next());
+ System.out.println(cb.next());
+ System.out.println(cb.next());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/combinationsandpermutations/CombinationSum.java b/src/main/java/combinationsandpermutations/CombinationSum.java
new file mode 100644
index 0000000..327eb8e
--- /dev/null
+++ b/src/main/java/combinationsandpermutations/CombinationSum.java
@@ -0,0 +1,125 @@
+package combinationsandpermutations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+public class CombinationSum {
+
+ public List> combinationSum(int[] candidates, int target) {
+ if (candidates == null || candidates.length == 0) return Collections.emptyList();
+ List> result = new ArrayList<>();
+
+ combinationSumUtil(candidates, target, result, new ArrayList<>(), 0);
+
+ return result;
+
+ }
+
+ public void combinationSumUtil(int[] candidates, int target, List> result, List tempList, int start) {
+ if (target < 0) return;
+ if (target == 0) {
+ result.add(new ArrayList<>(tempList));
+
+ }
+
+ for (int i = start; i < candidates.length; i++) {
+ if (target - candidates[i] < 0) break;
+ tempList.add(candidates[i]);
+ // The same repeated number may be chosen from candidates unlimited number of times.
+ // that's the reason of using i not i+1
+ combinationSumUtil(candidates, target - candidates[i], result, tempList, i);
+
+ tempList.remove(tempList.size() - 1);
+ }
+ }
+
+ public List> combinationSum2(int[] candidates, int target) {
+ if (candidates == null || candidates.length == 0) return Collections.emptyList();
+ List> result = new ArrayList<>();
+ Arrays.sort(candidates);
+ combinationSumUtil2(candidates, target, result, new ArrayList<>(), 0);
+
+ return result;
+ }
+
+ public void combinationSumUtil2(int[] candidates, int target, List> result, List tempList, int start) {
+ if (target < 0) return;
+
+ if (target == 0) {
+ result.add(new ArrayList<>(tempList));
+ return;
+ }
+
+ for (int i = start; i < candidates.length; i++) {
+// when we should skip a number? not just it's the same as previous number,
+// but also when it's previous number haven't been added!
+// i > cur means cand[i - 1] is not added
+// to the path (you should know why if you understand the algorithm),
+// so if cand[i] == cand[i-1], then we shouldn't add cand[i].
+// This tricky is very smart.
+
+ /**
+ * i>start && candidates[i]==candidates[i-1] :
+ * when input is like 1,1,2,4,7,8 and target is 9
+ * the first iteration would run for all combinations starts with 1 ([1,1,7], [1,8])
+ * the next number i=1 also starts with one which will run again for all combinations
+ * candidates[i]==candidates[i-1] this will eliminate the duplicate combinations(another [1,8])
+ */
+ if (i > start && candidates[i] == candidates[i - 1]) continue;
+ if (target - candidates[i] < 0) break;
+ tempList.add(candidates[i]);
+ combinationSumUtil2(candidates, target - candidates[i], result, tempList, i + 1);
+ tempList.remove(tempList.size() - 1);
+ }
+ }
+
+ public int combinationSum4BottomUp(int[] nums, int target) {
+ int[] dp = new int[target + 1];
+ dp[0] = 1;
+
+ // the difference with coin change is in coin change we see unique combination
+ // so outer loop is coins i.e we start with coins, but here we care about
+ // the number of permutations, so we start from target
+ // if you treat the nums as coins then we have unlimited number of coins
+ // that's the reason for the change in order
+ // For e.g. the classic coin change will exclude {2,1,1} after considering {1,1,2} as a solution.
+ /*
+ Coin change-2
+ for (int coin : coins) {
+ for (int i = 1; i <= amount; i++) {
+ if (i >= coin) {
+ dp[i] += dp[i - coin];
+ }
+ */
+ for (int i = 1; i <= target; i++) {
+ for (int num : nums) {
+ if (i - num >= 0) dp[i] += dp[i - num];
+ }
+ }
+ //System.out.println(Arrays.toString(dp));
+ return dp[target];
+ }
+
+ Integer[] cache;
+
+ public int combinationSum4(int[] nums, int target) {
+ return recursionHelper(nums, target, 0, new Integer[target + 1]);
+ }
+
+ private int recursionHelper(int[] nums, int target, int pos, Integer[] cache) {
+ if (pos == nums.length || target <= 0) {
+ return (target == 0) ? 1 : 0;
+ }
+
+ if (cache[target] != null) {
+ return cache[target];
+ }
+
+ int take = recursionHelper(nums, target - nums[pos], 0, cache);
+ int skip = recursionHelper(nums, target, pos + 1, cache);
+
+ return cache[target] = take + skip;
+ }
+}
diff --git a/src/main/java/combinationsandpermutations/FactorCombinations.java b/src/main/java/combinationsandpermutations/FactorCombinations.java
new file mode 100644
index 0000000..489681e
--- /dev/null
+++ b/src/main/java/combinationsandpermutations/FactorCombinations.java
@@ -0,0 +1,33 @@
+package combinationsandpermutations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * https://leetcode.com/problems/factor-combinations
+ */
+public class FactorCombinations {
+
+ public List> getFactors(int n) {
+ List> result = new ArrayList<>();
+ helper(result, new ArrayList(), n, 2);
+ return result;
+ }
+
+ public void helper(List> result, List item, int n, int start) {
+ if (n <= 1) {
+ if (item.size() > 1) {
+ result.add(new ArrayList<>(item));
+ }
+ return;
+ }
+
+ for (int i = start; i <= n; ++i) {
+ if (n % i == 0) {
+ item.add(i);
+ helper(result, item, n / i, i);
+ item.remove(item.size() - 1);
+ }
+ }
+ }
+}
diff --git a/src/main/java/combinationsandpermutations/Permutations.java b/src/main/java/combinationsandpermutations/Permutations.java
new file mode 100644
index 0000000..ead11cd
--- /dev/null
+++ b/src/main/java/combinationsandpermutations/Permutations.java
@@ -0,0 +1,73 @@
+package combinationsandpermutations;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * https://leetcode.com/problems/permutations/
+ */
+public class Permutations {
+
+ public List> permute(int[] nums) {
+ if (nums == null || nums.length == 0) return Collections.emptyList();
+ List> result = new ArrayList<>();
+ permuteUtils(nums, result, new ArrayList<>(), new HashSet<>());
+
+ return result;
+ }
+
+ public void permuteUtils(int[] nums, List> result, List tempList, Set set) {
+
+ if (tempList.size() == nums.length) {
+ result.add(new ArrayList<>(tempList));
+ return;
+ }
+
+ for (int num : nums) {
+// 1 + (permutations of 2, 3, 4)
+//
+// 2 + (permutations of 1, 3, 4)
+//
+// 3 + (permutations of 1, 2, 4)
+//
+// 4 + (permutations of 1, 2, 3)
+ if (set.contains(num)) continue;
+ tempList.add(num);
+ set.add(num);
+ permuteUtils(nums, result, tempList, set);
+ set.remove(tempList.get(tempList.size() - 1));
+ tempList.remove(tempList.size() - 1);
+ }
+ }
+
+ public List> permuteUnique(int[] nums) {
+ List> list = new ArrayList<>();
+ Arrays.sort(nums);
+ backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]);
+ return list;
+ }
+
+ private void backtrack(List> list, List tempList, int[] nums, boolean[] used) {
+ if (tempList.size() == nums.length) {
+ list.add(new ArrayList<>(tempList));
+ } else {
+ for (int i = 0; i < nums.length; i++) {
+ //[1, 1, 2][1, 2, 1][2, 1, 1]
+ //[1, 2, 3][1, 3, 2][2, 1, 3][2, 3, 1][3, 1, 2][3, 2, 1]
+ if (used[i] || i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue;
+ used[i] = true;
+ tempList.add(nums[i]);
+ backtrack(list, tempList, nums, used);
+ used[i] = false;
+ tempList.remove(tempList.size() - 1);
+ }
+ }
+ }
+
+}
+
+
diff --git a/src/main/java/combinationsandpermutations/SplitUniqueSubstring.java b/src/main/java/combinationsandpermutations/SplitUniqueSubstring.java
new file mode 100644
index 0000000..8a5aa75
--- /dev/null
+++ b/src/main/java/combinationsandpermutations/SplitUniqueSubstring.java
@@ -0,0 +1,42 @@
+package combinationsandpermutations;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class SplitUniqueSubstring {
+ public int maxUniqueSplit(String s) {
+ int[] result= new int[]{0};
+ recursionHelper(s, 0, new HashSet<>(), result);
+ return result[0];
+ }
+
+ /**
+ * if(start == s.length()) {
+ * max = Math.max(max, h.size());
+ * }
+ * String res = "";
+ *
+ * for(int i = start;i < s.length();i++) {
+ * res += s.charAt(i);
+ * if(h.contains(res)) continue;
+ * h.add(res);
+ * backtrack(s, i+1, h);
+ * h.remove(res);
+ * }
+ * }
+ */
+ public void recursionHelper(String s, int index, Set cache, int[] result){
+ if(index==s.length()) {
+ result[0]=Math.max(result[0],cache.size());
+ return;
+ }
+
+ for(int i= index;i> subsets(int[] nums) {
+ if(nums==null || nums.length==0) return Collections.emptyList();
+
+ List> result= new ArrayList<>();
+ subSetGenerationUtil(nums, result, new ArrayList<>(), 0);
+ return result;
+ }
+
+ public void subSetGenerationUtil(int[] nums, List> result, List tempList, int start){
+
+ result.add(new ArrayList<>(tempList));
+
+ for(int i=start;i> subsetsWithDup(int[] nums) {
+ if(nums==null || nums.length==0) return Collections.emptyList();
+
+ List> result= new ArrayList<>();
+ Arrays.sort(nums);
+ //subsetsWithDupUtil(nums, result, new ArrayList<>(), 0);
+ dfs(nums,0,result, new ArrayList<>());
+ return result;
+ }
+
+ public void subsetsWithDupUtil(int[] nums, List> result, List tempList, int start){
+ result.add(new ArrayList<>(tempList));
+
+ for(int i=start; istart && nums[i]==nums[i-1]) continue;
+ tempList.add(nums[i]);
+ subsetsWithDupUtil(nums, result, tempList, i+1);
+ tempList.remove(tempList.size()-1);
+ }
+ }
+
+ private void dfs(int[] nums, int index, List> res, List curr){
+ res.add(new ArrayList<>(curr));
+ if(index == nums.length){
+ return;
+ }
+ Set visited = new HashSet();
+ for(int i = index; i < nums.length; i++){
+ if(visited.add(nums[i])){
+ curr.add(nums[i]);
+ dfs(nums, i + 1, res, curr);
+ curr.remove(curr.size() - 1);
+ }
+ }
+ }
+
+ public static void main(String[] args) {
+ new SubSets().subsetsWithDup(new int[]{1,1,2,4});
+ }
+}
+
diff --git a/src/main/java/dynamicProgramming/AssemblyLineScheduling.java b/src/main/java/dynamicProgramming/AssemblyLineScheduling.java
new file mode 100644
index 0000000..fe61d10
--- /dev/null
+++ b/src/main/java/dynamicProgramming/AssemblyLineScheduling.java
@@ -0,0 +1,47 @@
+package dynamicProgramming;
+
+class AssemblyLineScheduling
+{
+ static int NUM_STATION = 4;
+
+ static int carAssembly(int a[][], int t[][], int e[], int x[])
+ {
+ int T1[]= new int [NUM_STATION];
+ int T2[] =new int[NUM_STATION] ;
+ int i;
+
+ // time taken to leave first station in line 1
+ T1[0] = e[0] + a[0][0];
+
+ // time taken to leave first station in line 2
+ T2[0] = e[1] + a[1][0];
+
+ // Fill tables T1[] and T2[] using
+ // the above given recursive relations
+ for (i = 1; i < NUM_STATION; ++i)
+ {
+ T1[i] = Math.min(T1[i - 1] + a[0][i],
+ T2[i - 1] + t[1][i] + a[0][i]);
+ T2[i] = Math.min(T2[i - 1] + a[1][i],
+ T1[i - 1] + t[0][i] + a[1][i]);
+ }
+
+ // Consider exit times and retutn minimum
+ return Math.min(T1[NUM_STATION-1] + x[0],
+ T2[NUM_STATION-1] + x[1]);
+ }
+
+
+ // Driver code
+ public static void main (String[] args)
+ {
+ int a[][] = {{4, 5, 3, 2},
+ {2, 10, 1, 4}};
+ int t[][] = {{0, 7, 4, 5},
+ {0, 9, 2, 8}};
+ int e[] = {10, 12}, x[] = {18, 7};
+
+ System.out.println(carAssembly(a, t, e, x));
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/BooleanParenthesization.java b/src/main/java/dynamicProgramming/BooleanParenthesization.java
new file mode 100644
index 0000000..af5ebea
--- /dev/null
+++ b/src/main/java/dynamicProgramming/BooleanParenthesization.java
@@ -0,0 +1,63 @@
+package dynamicProgramming;
+
+class BooleanParenthesization {
+ static int countParenth(char[] symb, char[] oper, int n) {
+ int[][] F = new int[n][n];
+ int[][] T = new int[n][n];
+
+ // Fill diagonal entries first
+ // All diagonal entries in T[i][i]
+ // are 1 if symbol[i] is T (true).
+ // Similarly, all F[i][i] entries
+ // are 1 if symbol[i] is F (False)
+ for (int i = 0; i < n; i++) {
+ F[i][i] = (symb[i] == 'F') ? 1 : 0;
+ T[i][i] = (symb[i] == 'T') ? 1 : 0;
+ }
+
+ // Now fill T[i][i+1], T[i][i+2],
+ // T[i][i+3]... in order And F[i][i+1],
+ // F[i][i+2], F[i][i+3]... in order
+ for (int gap = 1; gap < n; ++gap) {
+ for (int i = 0, j = gap; j < n; ++i, ++j) {
+ T[i][j] = F[i][j] = 0;
+ for (int g = 0; g < gap; g++) {
+ // Find place of parenthesization
+ // using current value of gap
+ int k = i + g;
+
+ // Store Total[i][k] and Total[k+1][j]
+ int tik = T[i][k] + F[i][k];
+ int tkj = T[k + 1][j] + F[k + 1][j];
+
+ // Follow the recursive formulas
+ // according to the current operator
+ if (oper[k] == '&') {
+ T[i][j] += T[i][k] * T[k + 1][j];
+ F[i][j] += (tik * tkj - T[i][k] * T[k + 1][j]);
+ }
+ if (oper[k] == '|') {
+ F[i][j] += F[i][k] * F[k + 1][j];
+ T[i][j] += (tik * tkj - F[i][k] * F[k + 1][j]);
+ }
+ if (oper[k] == '^') {
+ T[i][j] += F[i][k] * T[k + 1][j] + T[i][k] * F[k + 1][j];
+ F[i][j] += T[i][k] * T[k + 1][j] + F[i][k] * F[k + 1][j];
+ }
+ }
+ }
+ }
+ return T[0][n - 1];
+ }
+
+ public static void main(String[] args) {
+ char symbols[] = "TTFT".toCharArray();
+ char operators[] = "|&^".toCharArray();
+ int n = symbols.length;
+
+ // There are 4 ways
+ // ((T|T)&(F^T)), (T|(T&(F^T))),
+ // (((T|T)&F)^T) and (T|((T&F)^T))
+ System.out.println(countParenth(symbols, operators, n));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/BoxStacking.java b/src/main/java/dynamicProgramming/BoxStacking.java
new file mode 100644
index 0000000..24f8b7e
--- /dev/null
+++ b/src/main/java/dynamicProgramming/BoxStacking.java
@@ -0,0 +1,155 @@
+package dynamicProgramming;
+
+import java.util.Arrays;
+
+/**
+ * Date 05/09/2015
+ *
+ * @author tusroy
+ *
+ * 1) Create all rotations of boxes such that length is always greater
+ * or equal to width 2) Sort boxes by base area in non increasing order
+ * (length * width). This is because box with more area will never ever
+ * go on top of box with less area. 3) Take T[] and result[] array of
+ * same size as total boxes after all rotations are done 4) Apply
+ * longest increasing subsequence type of algorithm to get max height.
+ *
+ *
+ * References
+ * http://www.geeksforgeeks.org/dynamic-programming-set-21-box-stacking-problem/
+ * http://people.cs.clemson.edu/~bcdean/dp_practice/
+ */
+public class BoxStacking {
+ //We can use multiple instances of boxes. What it means is, we can have two different rotations of a box as part of our maximum height stack.
+
+ /**
+ * You can rearrange any cuboid's dimensions by rotating it to put it on another cuboid.
+ * So for each cuboid, we sort its length in three dimension.
+ *
+ * You can place cuboid i on cuboid j,
+ * we have
+ * width[i] <= width[j] and length[i] <= length[j] and height[i] <= height[j].
+ *
+ * This condition will hold, after we sort each cuboid length,
+ * that is,
+ * small[i] <= small[j] and mid[i] <= mid[j] and big[i] <= big[j].
+ */
+ public int maxHeight(int[][] cuboids) {
+ for (int[] cube : cuboids) Arrays.sort(cube);
+ Arrays.sort(cuboids, (a, b) -> (a[0] + a[1] + a[2]) - (b[0] + b[1] + b[2]));
+ int N = cuboids.length, res = 0;
+ int[] dp = new int[N];
+ for (int i = 0; i < N; i++) {
+ dp[i] = cuboids[i][2];
+ res = Math.max(res, dp[i]);
+ }
+ for (int i = 1; i < N; i++)
+ for (int j = 0; j < i; j++)
+ if (cuboids[j][0] <= cuboids[i][0] &&
+ cuboids[j][1] <= cuboids[i][1] &&
+ cuboids[j][2] <= cuboids[i][2]) {
+ dp[i] = Math.max(dp[i], dp[j] + cuboids[i][2]);
+ res = Math.max(res, dp[i]);
+ }
+ return res;
+ }
+
+ public int maxHeight(Dimension[] input) {
+ Dimension[] allRotationInput = new Dimension[input.length * 3];
+ createAllRotation(input, allRotationInput);
+
+ Arrays.sort(allRotationInput);
+
+ System.out.println(Arrays.toString(allRotationInput));
+
+ int[] T = new int[allRotationInput.length];
+ int[] result = new int[allRotationInput.length];
+
+ for (int i = 0; i < T.length; i++) {
+ T[i] = allRotationInput[i].height;
+ result[i] = i;
+ }
+
+ for (int i = 1; i < T.length; i++) {
+ for (int j = 0; j < i; j++) {
+ if (allRotationInput[i].length < allRotationInput[j].length
+ && allRotationInput[i].width < allRotationInput[j].width) {
+ if (T[j] + allRotationInput[i].height > T[i]) {
+ T[i] = T[j] + allRotationInput[i].height;
+ result[i] = j;
+ }
+ }
+ }
+ }
+
+ int max = Integer.MIN_VALUE;
+ for (int j : T) {
+ if (j > max) {
+ max = j;
+ }
+ }
+
+ return max;
+ }
+
+ private void createAllRotation(Dimension[] input, Dimension[] allRotationInput) {
+ int index = 0;
+ for (int i = 0; i < input.length; i++) {
+ allRotationInput[index++] = Dimension.createDimension(input[i].height, input[i].length, input[i].width);
+ allRotationInput[index++] = Dimension.createDimension(input[i].length, input[i].height, input[i].width);
+ allRotationInput[index++] = Dimension.createDimension(input[i].width, input[i].length, input[i].height);
+
+ }
+ }
+
+ public static void main(String args[]) {
+ BoxStacking bs = new BoxStacking();
+ Dimension[] input = {new Dimension(3, 2, 5), new Dimension(1, 2, 4)};
+ int maxHeight = bs.maxHeight(input);
+ System.out.println("Max height is " + maxHeight);
+ assert 11 == maxHeight;
+ }
+
+
+ static class Dimension implements Comparable {
+ int height;
+ int length;
+ int width;
+
+ Dimension(int height, int length, int width) {
+ this.height = height;
+ this.length = length;
+ this.width = width;
+ }
+
+ Dimension() {
+ }
+
+ static Dimension createDimension(int height, int side1, int side2) {
+ Dimension d = new Dimension();
+ d.height = height;
+ if (side1 >= side2) {
+ d.length = side1;
+ d.width = side2;
+ } else {
+ d.length = side2;
+ d.width = side1;
+ }
+ return d;
+ }
+
+ @Override
+ public int compareTo(Dimension d) {
+ if (this.length * this.width >= d.length * d.width) {
+ return 1;
+ } else {
+ return -1;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Dimension [height=" + height + ", length=" + length + ", width=" + width + "]";
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/CatalanNumberBinarySearchTree.java b/src/main/java/dynamicProgramming/CatalanNumberBinarySearchTree.java
new file mode 100644
index 0000000..f439f1a
--- /dev/null
+++ b/src/main/java/dynamicProgramming/CatalanNumberBinarySearchTree.java
@@ -0,0 +1,81 @@
+package dynamicProgramming;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * https://www.youtube.com/watch?v=0pTN0qzpt-Y
+ */
+public class CatalanNumberBinarySearchTree {
+ public int countTrees(int n) {
+ int[] T = new int[n + 1];
+ T[0] = 1;
+ T[1] = 1;
+ for (int i = 2; i <= n; i++) {
+ for (int j = 0; j < i; j++) {
+ int i1 = T[j] * T[i - j - 1];
+ System.out.println("T[" + j + "]" + "*" + "T[" + (i - j - 1) + "] :: " + i1);
+ T[i] += i1;
+ }
+ }
+ return T[n];
+ }
+
+ Integer[] cache = new Integer[20];
+
+ public int numTrees(int n) {
+ if (n < 0) return 0;
+ if (n == 0) return 1;
+ if (n == 1) return 1;
+ int result = 0;
+ if (cache[n] != null) return cache[n];
+ for (int k = 1; k <= n; k++) {
+ result += numTrees(k - 1) * numTrees(n - k);
+ }
+ return cache[n] = result;
+ }
+
+ /**
+ * Given a sequence 1…n, to construct a Binary Search Tree (BST) out of the sequence,
+ * we could enumerate each number i in the sequence, and use the number as the root,
+ * naturally, the subsequence 1…(i-1) on its left side would lay on the left branch of the root,
+ * and similarly the right subsequence (i+1)…n lay on the right branch of the root.
+ * We then can construct the subtree from the subsequence recursively.
+ * Through the above approach, we could ensure that the BST that we construct are all unique,
+ * since they have unique roots.
+ *
+ * G(n) = F(1, n) + F(2, n) + ... + F(n, n).
+ *
+ * For example, F(3, 7): the number of unique BST tree with number 3 as its root.
+ * To construct an unique BST out of the entire sequence [1, 2, 3, 4, 5, 6, 7] with 3 as the root,
+ * which is to say, we need to construct an unique BST out of its left subsequence [1, 2]
+ * and another BST out of the right subsequence [4, 5, 6, 7], and then combine them together (i.e. cartesian product).
+ * The tricky part is that we could consider the number of unique BST out of sequence [1,2] as G(2),
+ * and the number of of unique BST out of sequence [4, 5, 6, 7] as G(4). Therefore, F(3,7) = G(2) * G(4).
+ *
+ * F(i, n) = G(i-1) * G(n-i) 1 <= i <= n
+ * @param n
+ * @return
+ */
+ public int numTreesBottomUp(int n) {
+ if (n < 0) return 0;
+ int[] cache = new int[20];
+ cache[0] = 1;
+ cache[1] = 1;
+ for (int i = 2; i <= n; i++) {
+ for (int j = 1; j <= i; j++) {
+ System.out.println(j - 1+" : "+(i - j));
+ cache[i] += cache[j - 1] * cache[i - j];
+ }
+ }
+ return cache[n];
+ }
+
+ public static void main(String[] args) {
+ CatalanNumberBinarySearchTree cnt = new CatalanNumberBinarySearchTree();
+ System.out.println();
+ System.out.println(cnt.numTreesBottomUp(5));
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/EggDropping.java b/src/main/java/dynamicProgramming/EggDropping.java
new file mode 100644
index 0000000..8d2bb77
--- /dev/null
+++ b/src/main/java/dynamicProgramming/EggDropping.java
@@ -0,0 +1,59 @@
+package dynamicProgramming;
+
+/**
+ * http://www.geeksforgeeks.org/dynamic-programming-set-11-egg-dropping-puzzle/
+ *
+ * https://www.youtube.com/watch?v=3hcaVyX00_4&t=258s
+ */
+public class EggDropping {
+ // calculate minimum tries to try to find the floor which breaks the egg
+ public int calculate(int eggs, int floors) {
+
+ int[][] T = new int[eggs + 1][floors + 1];
+ int c = 0;
+ // We need one trial for one floor
+ for (int i = 0; i <= floors; i++) {
+ T[1][i] = i;
+ }
+
+ for (int e = 2; e <= eggs; e++) {
+ for (int f = 1; f <= floors; f++) {
+ T[e][f] = Integer.MAX_VALUE;
+ for (int k = 1; k <= f; k++) { // for loop to go from 0-f floor
+ // if egg breaks then egg-1 and floor -1 ==> T[e - 1][k - 1]
+ // else no change in egg count and remaining floors which is f-k ==> T[e][f - k]
+ // k means which floor we are in -- > first floor , second floor
+ // 2 Eggs -> 3 Floors
+ // • 2 Eggs -> 1 Floor-> 1,0 ,, 2,2(remaining floors)
+ // • 2 Eggs -> 2nd Floor -> 1,1 ,, 2,1 (remaining floors)
+ // 2 Eggs -> 3rd Floor -> 1,2 ,, 2,0 (remaining floors)
+ System.out.println("e - " + e + " :: f - " + f + " :: k - " + k);
+ System.out.println("T[" + (e - 1) + "][" + (k - 1) + "],T[" + e + "][" + (f - k) + "]");
+ c = 1 + Math.max(T[e - 1][k - 1], T[e][f - k]);
+ if (c < T[e][f]) {
+ T[e][f] = c;
+ }
+ }
+ }
+ }
+ return T[eggs][floors];
+ }
+
+ public static int superEggDrop(int K, int N) {
+ int[][] dp = new int[N + 1][K + 1];
+ int m = 0;
+ while (dp[m][K] < N) {
+ ++m;
+ for (int k = 1; k <= K; ++k)
+ dp[m][k] = dp[m - 1][k - 1] + dp[m - 1][k] + 1;
+ }
+ return m;
+ }
+
+ public static void main(String args[]) {
+ EggDropping ed = new EggDropping();
+ // System.out.println(ed.calculate(2, 6));
+ System.out.println(superEggDrop(2, 6));
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/KnightDialer.java b/src/main/java/dynamicProgramming/KnightDialer.java
new file mode 100644
index 0000000..d6e8332
--- /dev/null
+++ b/src/main/java/dynamicProgramming/KnightDialer.java
@@ -0,0 +1,73 @@
+package dynamicProgramming;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * https://leetcode.com/problems/knight-dialer/
+ */
+public class KnightDialer {
+ int[][] pos = new int[][]{{2, -1}, {2, 1}, {1, -2}, {1, 2}, {-1, 2}, {-1, -2}, {-2, -1}, {-2, 1}};
+ int max = (int) Math.pow(10, 9) + 7;
+ Map cache = new HashMap<>();
+
+ public int knightDialer(int n) {
+ long s = 0;
+ //do n hops from every i, j index (the very requirement of the problem)
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 3; j++) {
+ s = (s + recursionHelper(n, i, j)) % max;
+ }
+ }
+ return (int) s;
+ }
+
+ public int recursionHelper(int n, int i, int j) {
+ if (i < 0 || j < 0 || i >= 4 || j >= 3 || (i == 3 && j != 1)) return 0;
+
+ if (1 == n) return 1;
+ String key = i + "" + j + "" + n;
+ if (cache.containsKey(key)) return cache.get(key);
+
+ int res = 0;
+ for (int[] p : pos) {
+ res += recursionHelper(n - 1, i + p[0], j + p[1]);
+ res %= max;
+ }
+ cache.put(key, res);
+ return cache.get(key);
+ }
+
+ public static int knightDialerBottomUp(int n) {
+ int MOD = 1000000007;
+ int[][] paths = {{4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4}}; // Previous moves of knight-> For instance, if a knight is at 0, it reached from either 4 or 6. Similarly if it is at 1, it is reached from 7 or 9 & so on
+ int[][] dp = new int[n + 1][10]; // rows -> no of steps taken to reach row i cols-> no of digits
+ for (int j = 0; j < 10; j++)
+ dp[1][j] = 1; //populate the base case for n =1
+
+ for (int i = 2; i <=n ; i++) { // no of steps taken by knight to reach i
+ for (int j = 0; j < 10; j++) { // no of digits
+ for (int p : paths[j]) { // Previous move of knight in order to reach digit j
+ dp[i][j] += dp[i - 1][p]; // cumulatively add from the previous knight move. For instance., F(2, 0) -> F(1,4) + F(1,6) F(2,6) -> F(1,0) + F(1,1) + F(1,7)
+ }
+ dp[i][j] %= MOD;
+ }
+ }
+
+ for (int i = 0; i <=n ; i++) { // no of steps taken by knight to reach i
+ for (int j = 0; j < 10; j++) {
+ System.out.print(dp[i][j] +" ");
+ }
+ System.out.println();
+ }
+
+ double sum = 0d;
+ for (int j = 0; j < 10; j++)
+ sum += dp[n][j];
+ return (int) (sum % MOD);
+ }
+
+ public static void main(String[] args) {
+ System.out.println(knightDialerBottomUp(3));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/LastStoneWeight.java b/src/main/java/dynamicProgramming/LastStoneWeight.java
new file mode 100644
index 0000000..48bdf55
--- /dev/null
+++ b/src/main/java/dynamicProgramming/LastStoneWeight.java
@@ -0,0 +1,111 @@
+package dynamicProgramming;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * https://leetcode.com/problems/last-stone-weight-ii/
+ *
+ * https://www.youtube.com/watch?v=TaZxJt4-FHk
+ *
+ * For example, we take array [2,3,3,2,5]. We partition it into two sets [2,3,2] and [3,5], with sum 7 and 8 respectively.
+ * If we have collision with numbers from set 1 with those of set 2, only 7~8=1 will remain.
+ * so this becomes subset sum with min difference
+ *
+ * So the problem asks us to accumulate stones such the result is minimum,
+ * but it really is this problem in disguise, divide the array into two subsets such that their sum is minimum. Why?
+ * Suppose given array is [1,5,3,2] and you go about solving the problem as given you would take the following steps right?
+ *
+ * 5 - 3 = 2
+ * 2 - 2 = 0 (or) 2 - (5 - 3)
+ * 1 - 0 = 1 (or) 1 - (2 - (5 - 3)) => sum{1,5} - sum{2,3}
+ * So do you see why we want the minimum difference between two subsets?(this is just intuition not exact mathematical proof)
+ */
+public class LastStoneWeight {
+ static Map cache = new HashMap<>();
+
+ public static int lastStoneWeightIIRecur(int[] stones) {
+
+ int ans = recursionHelper(stones, 0, 0, 0);
+ cache.forEach((key, value) -> System.out.print(key + " :: " + value + ""));
+ return ans;
+ }
+
+ public static int recursionHelper(int[] stones, int index, int sum1, int sum2) {
+ if (index == stones.length) {
+ return Math.abs(sum1 - sum2);
+ }
+ String uniqueKey = index+"-"+sum1 + "-" + sum2;
+
+ if (cache.containsKey(uniqueKey)) {
+ return cache.get(uniqueKey);
+ }
+ int leftPath = recursionHelper(stones, index + 1, sum1 + stones[index], sum2);
+ int rightPath = recursionHelper(stones, index + 1, sum1, sum2 + stones[index]);
+
+ cache.put(uniqueKey, Math.min(leftPath, rightPath));
+ return cache.get(uniqueKey);
+
+ }
+
+ public static void main(String[] args) {
+ lastStoneWeightII2D(new int[]{31,26,33,21,40});
+ }
+
+ public static int lastStoneWeightII(int[] stones) {
+
+ int total = 0;
+ for (int stone : stones) total += stone;
+ int S2 = 0;
+ int target = total/2;
+ boolean[] dp = new boolean[target + 1]; // use only 1D array to store the status
+ dp[0] = true;
+ for (int s : stones) {
+ boolean[] cur = dp.clone();
+ for (int i = s; i <= target; i++) { // wont affect the value that is smaller than current stone's weight
+ if (dp[i - s]) { // checks if the subset sum is there if i=9 and s=7 at 9th pos true entry
+ // will be present because the 9-7=2 is there, like wise it checks for all combinations
+ cur[i] = true;
+ S2 = Math.max(S2, i);
+ }
+ }
+ dp = cur;
+ }
+ return total - 2 * S2;
+ }
+ public static int lastStoneWeightII2D(int[] stones) {
+ int n = stones.length, sum = 0;
+ for (int s : stones) sum += s;
+ int target = sum/2;
+
+ int[][] dp = new int[n + 1][target + 1];
+ for (int i = 1; i <= n; i++) {
+ int currStone = stones[i-1];
+ for (int j = 0; j <= target; j++) {
+ if (j >= currStone) {
+ dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - currStone] + currStone);
+ } else {
+ dp[i][j] = dp[i - 1][j];
+ }
+ }
+ }
+
+ System.out.println("Sum is :: "+sum);
+ for(int []d:dp){
+ System.out.println(Arrays.toString(d));
+ }
+ System.out.println(sum +" - "+ 2 * dp[n][target]);
+
+ /** dp[n][target] -> this is closest we can partition to sum/2
+ * //notice that in general I can say that
+ * //answer = S1-S2
+ * //where S1 is sum of some numbers and S2 is sum of rest of numbers
+ * //also note that S1+S2 = SUM (sum of all numbers)
+ * //S1 >= S2 because negative answer is not possible
+ * //now we have to minimise answer
+ * //answer = (SUM-S2)-S2 = > SUM-2*S2 (Just substituting S1 by SUM-S2)
+ */
+ return sum - 2 * dp[n][target];
+ }
+}
diff --git a/src/main/java/dynamicProgramming/MakeArrayStrictlyIncreasing.java b/src/main/java/dynamicProgramming/MakeArrayStrictlyIncreasing.java
new file mode 100644
index 0000000..03a7769
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MakeArrayStrictlyIncreasing.java
@@ -0,0 +1,32 @@
+package dynamicProgramming;
+
+/**
+ * https://leetcode.com/problems/remove-one-element-to-make-the-array-strictly-increasing
+ */
+public class MakeArrayStrictlyIncreasing {
+ public boolean canBeIncreasing(int[] nums) {
+ int numberOfDeletionsNeededToMakeStrictlyIncreasing = 0;
+ for (int i = 1; i < nums.length; i++) {
+ if (nums[i - 1] >= nums[i]) {
+
+ int iMinusTwoValue = i - 2 < 0 ? Integer.MIN_VALUE : nums[i - 2];
+ int iPlusOneValue = i + 1 == nums.length ? Integer.MAX_VALUE : nums[i + 1];
+
+ //[1,2,10,5,7]
+ //[2,3,1,2] -- false
+ //[1,1,1] -- false
+ //[100,21,100]
+ //[1,2,3]
+ //[105,924,32,968]
+ if ((nums[i] > iMinusTwoValue && nums[i] < iPlusOneValue) ||
+ (nums[i - 1] > iMinusTwoValue && nums[i - 1] < iPlusOneValue)) {
+ ++numberOfDeletionsNeededToMakeStrictlyIncreasing;
+ } else {
+ return false; // found an unfixable non-increase
+ }
+
+ }
+ }
+ return numberOfDeletionsNeededToMakeStrictlyIncreasing <= 1;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/MaxGoldAMinerCanGet.java b/src/main/java/dynamicProgramming/MaxGoldAMinerCanGet.java
new file mode 100644
index 0000000..9948d0c
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MaxGoldAMinerCanGet.java
@@ -0,0 +1,48 @@
+package dynamicProgramming;
+
+import java.util.Arrays;
+
+/**
+ * Freshworks interview question:
+ * Miner can start at any of the i,j in first column
+ * miner can move in right, right upper diagonal and right lower diagonal
+ */
+public class MaxGoldAMinerCanGet {
+
+ public static int getMaxGoldMinerCanGet(int[][] matrix) {
+ if (matrix.length == 0) return 0;
+
+ int m = matrix.length;
+ int n = matrix[0].length;
+ int result = -1;
+ for (int j = 1; j < n; j++) {
+ for (int i = 0; i < m; i++) {
+ int left = matrix[i][j - 1];
+ int leftUpperDiagonal = i - 1 >= 0 ? matrix[i - 1][j - 1] : 0;
+ int leftLowerDiagonal = i + 1 < m ? matrix[i + 1][j - 1] : 0;
+
+ matrix[i][j] = Math.max(left, Math.max(leftUpperDiagonal, leftLowerDiagonal)) + matrix[i][j];
+ result = Math.max(result, matrix[i][j]);
+ }
+ }
+
+ for (int[] ints : matrix) {
+ System.out.println(Arrays.toString(ints));
+ }
+
+ return result;
+
+ }
+
+ public static void main(String[] args) {
+ System.out.println(getMaxGoldMinerCanGet(new int[][]{{1, 3, 1, 5},
+ {2, 2, 4, 1},
+ {5, 0, 2, 3},
+ {0, 6, 1, 2}}
+ ));
+ System.out.println(getMaxGoldMinerCanGet(new int[][]{{1, 3, 3},
+ {2, 1, 4},
+ {0, 6, 4}}
+ ));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/MaxSumForNonAdjacentElements.java b/src/main/java/dynamicProgramming/MaxSumForNonAdjacentElements.java
new file mode 100644
index 0000000..684486b
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MaxSumForNonAdjacentElements.java
@@ -0,0 +1,27 @@
+package dynamicProgramming;
+
+/**
+ * @author Tushar Roy
+ *
+ * https://www.geeksforgeeks.org/maximum-sum-such-that-no-two-elements-are-adjacent/
+ */
+public class MaxSumForNonAdjacentElements {
+
+ public int maxSum(int arr[]) {
+ int excl = 0;
+ int incl = arr[0];
+ for (int i = 1; i < arr.length; i++) {
+ int oldResult = incl;
+ incl = Math.max(excl + arr[i], incl);
+ excl = oldResult;
+ }
+ return incl;
+ }
+
+ public static void main(String args[]) {
+ MaxSumForNonAdjacentElements msn = new MaxSumForNonAdjacentElements();
+ int arr[] = { 4, 1, 1, 4, 2, 1 };
+ System.out.println(msn.maxSum(arr));
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/MaximumRectangle.java b/src/main/java/dynamicProgramming/MaximumRectangle.java
new file mode 100644
index 0000000..b866d13
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MaximumRectangle.java
@@ -0,0 +1,99 @@
+package dynamicProgramming;
+
+import practiceproblems.stack.MaxHistogram;
+
+import java.util.Arrays;
+
+/**
+ * At every row the height and area of rectangle varies, if the last row(base) is having a zero value
+ * then that portion have to be avoided, this is the reason we take maxHistogram after every row
+ *
+ * matrix
+ * 0 0 0 1 0 0 0
+ * 0 0 1 1 1 0 0
+ * 0 1 1 1 1 1 0
+ *
+ * height
+ * 0 0 0 1 0 0 0
+ * 0 0 1 2 1 0 0
+ * 0 1 2 3 2 1 0
+ */
+public class MaximumRectangle {
+
+ public static int maximalRectangle(char[][] matrix) {
+ if (matrix.length == 0) return 0;
+ int[] row = new int[matrix[0].length];
+ int result = 0;
+ for (char[] arr : matrix) {
+ int i = 0;
+ // for each cell with value=1, we look upward (north), the number of continuous '1' is the height of cell
+ //First initiate the height array as 1 1 0 1 0 1, which is just a copy of the first row. Then we can easily calculate the max area is 2.
+ //Then update the array. We scan the second row, when the matrix[1][i] is 0, set the height[i] to 0
+ //else height[i] += 1, which means the height has increased by 1. So the height array again becomes 0 2 0 0 1 2.
+ // The max area now is also 2.
+ for (char c : arr) {
+ if (c - '0' > 0) {
+ row[i] += c - '0';
+ } else {
+ row[i] = 0;
+ }
+
+ i++;
+ }
+ /** The result row for every iteration
+ * [1, 0, 1, 0, 0]
+ * [2, 0, 2, 1, 1]
+ * [3, 1, 3, 2, 2]
+ * [4, 0, 0, 3, 0]
+ */
+ System.out.println(Arrays.toString(row));
+ result = Math.max(result, MaxHistogram.largestRectangleArea(row));
+ }
+
+ return result;
+ }
+
+ public static void main(String[] args) {
+ maximalRectangle(new char[][]{{'1', '0', '1', '0', '0'},
+ {'1', '0', '1', '1', '1'},
+ {'1', '1', '1', '1', '1'},
+ {'1', '0', '0', '1', '0'}});
+ }
+
+ /**
+ * https://www.youtube.com/watch?v=-FgseNO-6Gk
+ */
+ public int maximalRectangleBruteForce(char[][] matrix) {
+ int rowLength = matrix.length;
+ if (rowLength == 0) return 0;
+ int colLength = matrix[0].length;
+ if (colLength == 0) return 0;
+
+ int maxA = Integer.MIN_VALUE;
+
+ for (int row = 0; row < rowLength; row++) {
+ for (int col = 0; col < colLength; col++) {
+ if (matrix[row][col] == '0') continue;
+ // consider the rectangle whose upper left corner is at [r, c]:
+
+ int rightMostCol = colLength - 1;// the right most column that we should check, initially it's w-1
+
+ // iterate from i,j till row and col end
+ for (int r1 = row; r1 < rowLength; r1++) {
+ for (int c1 = col; c1 <= rightMostCol; c1++) {
+
+ if (matrix[r1][c1] == '0') {
+ rightMostCol = c1 - 1; // update the rightMostCol when we encounter '0', no use in proceeding after
+ break; // go to next row
+ }
+ // r1 - row + 1, c1 - col + 1 are rectangle size relative to i,j where the inner loop started
+ maxA = Math.max(maxA, (r1 - row + 1) * (c1 - col + 1)); //
+ }
+ }
+ }
+ }
+
+ return Math.max(maxA, 0);
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/MinCoinChange.java b/src/main/java/dynamicProgramming/MinCoinChange.java
new file mode 100644
index 0000000..dfedffb
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MinCoinChange.java
@@ -0,0 +1,50 @@
+package dynamicProgramming;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/coin-change-2/
+ */
+public class MinCoinChange {
+
+ Integer[] cache;
+
+ public int coinChange(int[] coins, int amount) {
+ cache = new Integer[amount + 1];
+ return recursionHelper(amount, coins);
+ }
+
+ public int recursionHelper(int amount, int[] coins) {
+ if (amount == 0) return 0;
+ if (amount < 0) return -1;
+
+ if (cache[amount] != null) return cache[amount];
+
+ int minCount = Integer.MAX_VALUE;
+
+ for (int coin : coins) {
+ int count = recursionHelper(amount - coin, coins);
+ if (count == -1) continue;
+ minCount = Math.min(minCount, count + 1);
+ }
+
+ return cache[amount] = minCount == Integer.MAX_VALUE ? -1 : minCount;
+
+ }
+
+
+ public int coinChangeBottomUp(int[] coins, int amount) {
+ Integer[] cache = new Integer[amount + 1];
+ Arrays.fill(cache, amount + 1);
+ cache[0] = 0;
+ for (int coin : coins) {
+ for (int i = 1; i <= amount; i++) {
+ if (i - coin >= 0) {
+ cache[i] = Math.min(cache[i], cache[i - coin] + 1);
+ }
+ }
+ }
+
+ return cache[amount] == amount + 1 ? -1 : cache[amount];
+ }
+}
diff --git a/src/main/java/dynamicProgramming/MinCostTickets.java b/src/main/java/dynamicProgramming/MinCostTickets.java
new file mode 100644
index 0000000..0d7a584
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MinCostTickets.java
@@ -0,0 +1,67 @@
+package dynamicProgramming;
+
+public class MinCostTickets {
+
+ //1,4,6,7,8,20
+ //2,7,50
+ public int mincostTickets(int[] days, int[] cost) {
+ int lastDayTravel = days[days.length - 1];
+
+ int[] daysDp = new int[lastDayTravel + 1];
+ boolean[] travelDays = new boolean[lastDayTravel + 1];
+
+ for (int day : days) {
+ travelDays[day] = true;
+ }
+
+ for (int i = 1; i <= lastDayTravel; i++) {
+
+ if (!travelDays[i]) {
+ daysDp[i] = daysDp[i - 1];
+ } else {
+ int oneDayPass = daysDp[i - 1] + cost[0];
+ int sevenDaysPass = daysDp[Math.max(0, i - 7)] + cost[1];
+ int thirtyDayPass = daysDp[Math.max(0, i - 30)] + cost[2];
+
+ daysDp[i] = Math.min(oneDayPass, Math.min(sevenDaysPass, thirtyDayPass));
+ }
+ }
+
+ return daysDp[lastDayTravel];
+ }
+
+
+ private int recursionUtil(int totalDaysOfTravel, boolean[] willTravel, int[] costs, Integer[] dp) {
+ if (totalDaysOfTravel <= 0) return 0;
+
+ if (dp[totalDaysOfTravel] != null) return dp[totalDaysOfTravel];
+
+ int daily;
+ if (willTravel[totalDaysOfTravel]) {
+ daily = recursionUtil(totalDaysOfTravel - 1, willTravel, costs, dp) + costs[0];// Corresponding to daily package
+ } else {
+ daily = recursionUtil(totalDaysOfTravel - 1, willTravel, costs, dp);// This is the case when we cant take daily package but still we need to make recursive call to change the state
+ }
+
+ int weekly = recursionUtil(totalDaysOfTravel - 7, willTravel, costs, dp) + costs[1];// Corresponding to weekly package
+ int monthly = recursionUtil(totalDaysOfTravel - 30, willTravel, costs, dp) + costs[2];// Corresponding to monthly package
+ dp[totalDaysOfTravel] = Math.min(daily, Math.min(weekly, monthly));
+ return dp[totalDaysOfTravel];
+
+ }
+
+ // Time Complexity-: O(N) Space Complexity -: O(366)
+ public int mincostTicketsRecur(int[] days, int[] costs) {
+ int totalDaysOfTravel = days[days.length - 1];
+ boolean[] willTravel = new boolean[totalDaysOfTravel+1];
+ for (int day : days) {
+ willTravel[day] = true;
+ }
+
+ Integer[] dp = new Integer[totalDaysOfTravel+1];
+ recursionUtil(totalDaysOfTravel, willTravel, costs, dp);
+ return dp[totalDaysOfTravel];
+ }
+
+
+}
diff --git a/src/main/java/dynamicProgramming/MinSwapsToMakeArrayIncreasing.java b/src/main/java/dynamicProgramming/MinSwapsToMakeArrayIncreasing.java
new file mode 100644
index 0000000..85061bc
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MinSwapsToMakeArrayIncreasing.java
@@ -0,0 +1,113 @@
+package dynamicProgramming;
+
+/**
+ * https://leetcode.com/problems/minimum-swaps-to-make-sequences-increasing/
+ */
+public class MinSwapsToMakeArrayIncreasing {
+ Integer[][] dp;
+ final int MAX = 10_000;
+
+ /**
+ * There are two states possible,
+ *
+ * Don't swap elements at the current index
+ * Swap elements at the current index
+ *
+ * We just have to find out which one gives the minimum number of swaps for the rest of the array.
+ * That is, we will compute answer for both the states.
+ * The answer for the current state is dependent on the relation between the element at the current index
+ * and the previous index.
+ *
+ * If they are already in increasing order, t
+ * hen the state for the current index is applied to the previous index
+ * (that is, no swap remains no swap, swap remains swap).
+ * Else, the state for the current index is reversed for the previous index.
+ * But, what if swap and no swap both achieve the increasing order? In this case,
+ * we take the minimum of both states from the previous index.
+ *
+ * @param A
+ * @param B
+ * @return
+ */
+ public int minSwapTopDown(int[] A, int[] B) {
+ dp = new Integer[A.length][2];
+ return minSwapHelper(A, B, 0, -1, -1, 0);
+ }
+
+ private int minSwapHelper(int[] A, int[] B, int i, int prevA, int prevB, int swapped) {
+
+ if (i == A.length) return 0;
+ if (dp[i][swapped] != null) return dp[i][swapped];
+
+ int minSwaps = MAX;
+
+ if (A[i] > prevA && B[i] > prevB) { // with-no-swap
+ minSwaps = minSwapHelper(A, B, i + 1, A[i], B[i], 0);
+ }
+
+ if (B[i] > prevA && A[i] > prevB) { // with-swap
+ minSwaps = Math.min(minSwaps, minSwapHelper(A, B, i + 1, B[i], A[i], 1) + 1);
+ }
+
+ dp[i][swapped] = minSwaps;
+ return minSwaps;
+ }
+
+ /**
+ * https://www.youtube.com/watch?v=mLTF2UXkd2o
+ * @return
+ */
+ public static int minSwap(int[] A, int[] B) {
+
+ int[] noSwap = new int[A.length];
+ int[] swap = new int[A.length];
+ swap[0] = 1;
+ for (int i = 1; i < A.length; ++i) {
+
+ /** // This is max value, could be anything as long as they are higher
+ // than max possible value (which would be A.length-1, since max
+ // swaps you can do is A.length-1)*/
+ noSwap[i] = A.length;
+ swap[i] = A.length;
+
+ if (A[i] > A[i - 1] && B[i] > B[i - 1]) {
+ /**
+ * We are here because this index does not need to swap.
+ // Great, what would be the cost to reach here and not swap?
+ // It'll be same as cost of not swapping for prev. index.
+ // Why dont we rather take min(noSwap[i-1], swap[i-1]), because
+ // in that case noSwap[i-1] will be min anyway.
+ */
+ noSwap[i] = noSwap[i - 1];
+
+
+ /** // what would be the cost to reach here and swap?
+ // It'll be cost of swapping for prev. index + 1.
+ // Why dont we rather take min(noSwap[i-1], swap[i-1]) + 1, because
+ // we are tracking optimistic swaps and if we do min, we will lose
+ // track of swaps that were needed and done in past.
+ */
+ swap[i] = swap[i - 1] + 1;
+
+ }
+ /**
+ * In this case, if we want to keep A and B increasing before the index i, can only have two choices.
+ * -> 2.1 swap at (i-1) and do not swap at i, we can get notswap[i] = Math.min(swap[i-1], notswap[i] )
+ * -> 2.2 do not swap at (i-1) and swap at i, we can get swap[i]=Math.min(notswap[i-1]+1, swap[i])
+ */
+ if (A[i] > B[i - 1] && B[i] > A[i - 1]) {
+ noSwap[i] = Math.min(noSwap[i], swap[i - 1]);
+ swap[i] = Math.min(noSwap[i - 1] + 1, swap[i]);
+ }
+ }
+
+ // Now that we cost of swapping and not swapping each index,
+ // answer is:
+ return Math.min(noSwap[A.length - 1], swap[A.length - 1]);
+ }
+
+ public static void main(String[] args) {
+
+ System.out.println(minSwap(new int[]{0, 4, 4, 5, 9}, new int[]{0, 1, 6, 8, 10}));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/MonotoneIncreasingString.java b/src/main/java/dynamicProgramming/MonotoneIncreasingString.java
new file mode 100644
index 0000000..45eaabb
--- /dev/null
+++ b/src/main/java/dynamicProgramming/MonotoneIncreasingString.java
@@ -0,0 +1,78 @@
+package dynamicProgramming;
+
+/**
+ * https://leetcode.com/problems/flip-string-to-monotone-increasing
+ */
+public class MonotoneIncreasingString {
+
+ /**
+ * * Algorithm:
+ * *
+ * * Skip 0's until we encounter the first 1.
+ * * Keep track of number of 1's in onesCount (Prefix).
+ * * Any 0 that comes after we encounter 1 can be a potential candidate for flip. Keep track of it in flipCount.
+ * * If flipCount exceeds oneCount - (Prefix 1's flipped to 0's)
+ * * a. Then we are trying to flip more 0's (suffix) than number of 1's (prefix) we have.
+ * * b. Its better to flip the 1's instead.
+ * @param s
+ * @return
+ */
+ public int minFlipsMonoIncr(String s) {
+ char[] ch = s.toCharArray();
+ int onescount = 0;
+ int flipcount = 0;
+
+ for (int i = 0; i < s.length(); i++) {
+ if (ch[i] == '0') {
+ if (onescount == 0) continue; // if all beginning char is zero, no need to flip
+ flipcount++; // flip 0 -> 1
+ } else {
+ onescount++; // flip 1 -> 0
+ }
+ if (flipcount > onescount) { // if flip 0-> 1 greater than flip 1 -> 0 then
+ flipcount = onescount; // then we choose flip 1 -> 0 for the left part
+ }
+ }
+
+ return flipcount;
+ }
+
+ /**
+ * LIS variation
+ * Thought:
+ * Since s is a binary string, so an increasing subsequence will either:
+ *
+ * end at '0'
+ * end at '1'
+ * For number of changes(flips) to be minimum
+ * we need to find the longest part of the string which can be left untouched (i.e which is already increasing).
+ *
+ * Implementation Details:
+ *
+ * So if s[i]=='0':
+ *
+ * current element can extend an increasing subsequence ending at '0'.
+ * else if s[i]=='1' current element can extend:
+ *
+ * an increasing subsequence ending at a '0'
+ * an increasing subsequence ending at a '1'
+ * which one to choose ? the one which is the largest out of 1) and 2).
+ * answer=s.size() - max(lis ending at 0, lis ending at 1)
+ */
+ public int MinFlipsMonoIncrLIS(String S)
+ {
+ int zeros = 0, increasingSeq = 0;
+
+ for(int i = 0; i < S.length(); i++)
+ {
+ if((S.charAt(i) - '0') == 0)
+ zeros++;
+ else
+ increasingSeq++;
+ // it can extend both lis ending at 0 and ending at 1 so will choose the best of 2
+ increasingSeq = Math.max(increasingSeq, zeros);
+ }
+
+ return S.length() - increasingSeq;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/NumberWithSameConsequtiveDifference.java b/src/main/java/dynamicProgramming/NumberWithSameConsequtiveDifference.java
new file mode 100644
index 0000000..7ab5a1f
--- /dev/null
+++ b/src/main/java/dynamicProgramming/NumberWithSameConsequtiveDifference.java
@@ -0,0 +1,57 @@
+package dynamicProgramming;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Return all non-negative integers of length N such that the absolute difference between every two consecutive digits is K.
+ *
+ * Note that every number in the answer must not have leading zeros except for the number 0 itself.
+ * For example, 01 has one leading zero and is invalid, but 0 is valid.
+ *
+ * You may return the answer in any order.
+ *
+ * Input: N = 3, K = 7
+ * Output: [181,292,707,818,929]
+ * Explanation: Note that 070 is not a valid number, because it has leading zeroes.
+ *
+ * Input: N = 2, K = 1
+ * Output: [10,12,21,23,32,34,43,45,54,56,65,67,76,78,87,89,98]
+ */
+public class NumberWithSameConsequtiveDifference {
+
+ // the idea is to create a tree with dfs of depth N and in each step(level) we add and subract the K to
+ // the last element and check if it falls under the boundray (0> && <10)
+ // for N=3 and K=2
+ // 1
+ // -K / \ +K
+ // -2 3
+ // / \
+ // 1 5 --> end of tree because N=3
+
+ public int[] numsSameConsecDiff(int N, int K) {
+ List result= new ArrayList<>();
+ if(N==1) result.add(0);
+
+ for(int i=1;i<10;i++){
+ dfs(N-1, K, result, i);
+ }
+ int[] ret = new int[result.size()];
+ for(int i = 0;i < ret.length;i++)
+ ret[i] = result.get(i);
+ return ret;
+ }
+
+ public void dfs(int N, int K, List result, int num){
+ if(N==0) {
+ result.add(num);
+ return;
+ }
+ int lastDigit= num%10;
+
+ if(lastDigit>=K) dfs(N-1,K,result,num*10+lastDigit-K);
+ if(K>0 && K+lastDigit<10) dfs(N-1,K,result,num*10+lastDigit+K);
+ }
+
+
+}
diff --git a/src/main/java/dynamicProgramming/OnesAndZeroes.java b/src/main/java/dynamicProgramming/OnesAndZeroes.java
new file mode 100644
index 0000000..49e16a7
--- /dev/null
+++ b/src/main/java/dynamicProgramming/OnesAndZeroes.java
@@ -0,0 +1,45 @@
+package dynamicProgramming;
+
+/**
+ * https://leetcode.com/problems/ones-and-zeroes/
+ */
+public class OnesAndZeroes {
+ private int[][][] memo;
+
+ public int findMaxForm(String[] strs, int m, int n) {
+ memo = new int[m + 1][n + 1][strs.length];
+ return findMaxFormFrom(strs, m, n, 0);
+ }
+
+ private int findMaxFormFrom(String[] strs, int m, int n, int si) {
+ if (si == strs.length || (m == 0 && n == 0)) {
+ return 0;
+ }
+ if (memo[m][n][si] > 0) {
+ return memo[m][n][si];
+ }
+ int cntIncludeStr = 0;
+ int zeros = countZeros(strs[si]);
+ int ones = strs[si].length() - zeros;
+ //for each string, we count the zeroes in it by countZeroesIn(String str) and see if there are enough 0s and 1s for it.
+ // If so, we accumulate that string and proceed with the remaining strings, 0s and 1s by means of the following code:
+ if (m >= zeros && n >= ones) {
+ cntIncludeStr = 1 + findMaxFormFrom(strs, m - zeros, n - ones, si + 1);
+ }
+ //We also take the other route, which simply skips the string and does not use any 0s and 1s.
+ int cntExcludeStr = findMaxFormFrom(strs, m, n, si + 1);
+ //Whichever is bigger, is that the result.
+ memo[m][n][si] = Math.max(cntIncludeStr, cntExcludeStr);
+ return memo[m][n][si];
+ }
+
+ private int countZeros(String s) {
+ int cntZero = 0;
+ for (char c : s.toCharArray()) {
+ if (c == '0') {
+ cntZero++;
+ }
+ }
+ return cntZero;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/OptimalStratergy.java b/src/main/java/dynamicProgramming/OptimalStratergy.java
new file mode 100644
index 0000000..5b47eb4
--- /dev/null
+++ b/src/main/java/dynamicProgramming/OptimalStratergy.java
@@ -0,0 +1,130 @@
+package dynamicProgramming;
+
+import java.util.Arrays;
+
+/**
+ * http://www.glassdoor.com/Interview/N-pots-each-with-some-number-of-gold-coins-are-arranged-in-a-line-You-are-playing-a-game-against-another-player-You-tak-QTN_350584.htm
+ *
+ * https://www.techiedelight.com/pots-gold-game-dynamic-programming/
+ */
+public class OptimalStratergy {
+ // Function to maximize the number of coins collected by a player,
+ // assuming that opponent also plays optimally
+ public static int optimalStrategy(int[] coin, int i, int j,
+ int[][] lookup) {
+ // base case: one pot left, only one choice possible
+ if (i == j) {
+ return coin[i];
+ }
+
+ // if we're left with only two pots, choose one with maximum coins
+ if (i + 1 == j) {
+ return Integer.max(coin[i], coin[j]);
+ }
+
+ // if sub-problem is seen for the first time, solve it and
+ // store its result in a lookup table
+ if (lookup[i][j] == 0) {
+ // if player chooses front coin i, opponent is left to choose
+ // from [i+1, j].
+ // 1. if opponent chooses front coin i+1, recur for [i+2, j]
+ // 2. if opponent chooses rear coin j, recur for [i+1, j-1]
+
+ int start = coin[i] + Integer.min(optimalStrategy(coin, i + 2,
+ j, lookup),
+ optimalStrategy(coin, i + 1, j - 1, lookup));
+
+ // if player chooses rear coin j, opponent is left to choose
+ // from [i, j-1].
+ // 1. if opponent chooses front coin i, recur for [i+1, j-1]
+ // 2. if opponent chooses rear coin j-1, recur for [i, j-2]
+
+ int end = coin[j] + Integer.min(optimalStrategy(coin, i + 1,
+ j - 1, lookup),
+ optimalStrategy(coin, i, j - 2, lookup));
+
+ // assign maximum of two choices
+ lookup[i][j] = Integer.max(start, end);
+ }
+
+ // return the subproblem solution from the map
+ return lookup[i][j];
+ }
+
+ // main function
+ public static void main(String[] args) {
+ // pots of gold arranged in a line
+ int[] coin = {4, 6, 2, 3};
+
+ // Create a table to store solutions of subproblems
+ int[][] lookup = new int[coin.length][coin.length];
+
+ System.out.println("Maximum coins collected by player is "
+ + optimalStrategy(coin, 0, coin.length - 1, lookup));
+ }
+
+ public boolean PredictTheWinner(int[] nums) {
+ Integer[][] dp = new Integer[nums.length + 1][nums.length + 1];
+ int playerA = recursionHelper(nums, 0, nums.length - 1, dp);
+ int playerB = Arrays.stream(nums).sum() - playerA;
+
+ return playerA >= playerB;
+ }
+
+ public int recursionHelper(int[] nums, int i, int j, Integer[][] dp) {
+
+ if (i > j) return 0;
+ if (i == j) return nums[i];
+ if (dp[i][j] != null) return dp[i][j];
+
+ int takeFront = nums[i] + Math.min(recursionHelper(nums, i + 2, j, dp), recursionHelper(nums, i + 1, j - 1, dp));
+ int takeBack = nums[j] + Math.min(recursionHelper(nums, i + 1, j - 1, dp), recursionHelper(nums, i, j - 2, dp));
+ return dp[i][j] = Math.max(takeFront, takeBack);
+ }
+
+ public boolean PredictTheWinnerBottomUp(int[] nums) {
+ int n = nums.length;
+
+ /*
+ dp[i][j] -> score of the first player for picks between nums[i..j]
+ */
+ int[][] dp = new int[n][n];
+
+ // total of nums
+ int total = 0;
+ for (int num : nums) {
+ total += num;
+ }
+
+ for (int len = 1; len <= n; len++) {
+ for (int i = 0; i + len <= n; i++) {
+ int j = i + len - 1;
+
+ /*
+ First player has option to choose i or j
+ If he chooses i then 2nd player to choose in (i+1, j)
+ - if 2nd player chooses i+1, then player 1 will next choose from (i+2,j)
+ - if 2nd player chooses j, then player 1 will next choose from (i+1,j-1)
+ If he chooses j then 2nd player to choose in (i, j-1)
+ - if 2nd player chooses i, then player 1 will next choose from (i+1,j-1)
+ - if 2nd player chooses j-1, then player 1 will next choose from (i,j-2)
+
+ We know that player 2 would have played wisely and player 1 will get the the minimum in the next move.
+ We choose the best(Max) of the above 2 scenarios
+ */
+ int a = (i + 1 < n && j - 1 >= 0) ? dp[i + 1][j - 1] : 0;
+ int b = (i + 2 < n) ? dp[i + 2][j] : 0;
+ int c = (j - 2 >= 0) ? dp[i][j - 2] : 0;
+
+ dp[i][j] = Math.max(nums[i] + Math.min(a, b), nums[j] + Math.min(a, c));
+ }
+ }
+
+ /*
+ dp[0][n-1] will have the score for the first player.
+ */
+ int player1Score = dp[0][n - 1];
+ int player2Score = total - player1Score;
+ return player1Score >= player2Score;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/OptimalTreeSearch.java b/src/main/java/dynamicProgramming/OptimalTreeSearch.java
new file mode 100644
index 0000000..5f7412f
--- /dev/null
+++ b/src/main/java/dynamicProgramming/OptimalTreeSearch.java
@@ -0,0 +1,47 @@
+package dynamicProgramming;
+/**
+ * http://www.geeksforgeeks.org/dynamic-programming-set-24-optimal-binary-search-tree/
+ */
+public class OptimalTreeSearch {
+
+ public int minCost(int input[], int freq[]){
+ int T[][] = new int[input.length][input.length];
+
+ for(int i=0; i < T.length; i++){
+ T[i][i] = freq[i];
+ }
+
+ for(int l = 2; l <= input.length; l++){
+ for(int i=0; i <= input.length-l; i++){
+ int j = i + l -1;
+ T[i][j] = Integer.MAX_VALUE;
+ int sum = getSum(freq, i, j);
+
+ for(int k=i; k <= j; k++){
+ int val = sum + (k-1 < i ? 0 : T[i][k-1]) +
+ (k+1 > j ? 0 : T[k+1][j]) ;
+ if(val < T[i][j]){
+ T[i][j] = val;
+ }
+ }
+ }
+ }
+ return T[0][input.length-1];
+ }
+
+ private int getSum(int freq[], int i, int j){
+ int sum = 0;
+ for(int x = i; x <= j; x++){
+ sum += freq[x];
+ }
+ return sum;
+ }
+
+
+ public static void main(String args[]){
+ int input[] = {10,12,20,35,46};
+ int freq[] = {34,8,50,21,16};
+ OptimalTreeSearch ots = new OptimalTreeSearch();
+ System.out.println(ots.minCost(input, freq));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/OutOfBounds.java b/src/main/java/dynamicProgramming/OutOfBounds.java
new file mode 100644
index 0000000..50ddb73
--- /dev/null
+++ b/src/main/java/dynamicProgramming/OutOfBounds.java
@@ -0,0 +1,32 @@
+package dynamicProgramming;
+
+/**
+ * https://leetcode.com/problems/out-of-boundary-paths/
+ */
+public class OutOfBounds {
+ int [][] dirs= new int[][]{{-1,0},{1,0},{0,-1},{0,1}};
+ int mod = 1000000000 + 7;
+ Integer[][][] cache;
+ public int findPaths(int m, int n, int maxMove, int startRow, int startColumn) {
+ cache= new Integer[m+1][n+1][maxMove+1];
+ return recursionHelper(m,n,maxMove,startRow,startColumn);
+ }
+
+ public int recursionHelper(int m, int n, int maxMove, int startRow, int startColumn){
+
+ if(startRow<0 || startRow>=m || startColumn<0 || startColumn>=n) return 1;
+ if(maxMove==0) return 0;
+
+ if(cache[startRow][startColumn][maxMove]!=null) return cache[startRow][startColumn][maxMove];
+
+ int result=0;
+
+ for(int[] dir:dirs){
+ result= result+recursionHelper(m,n,maxMove-1,startRow+dir[0],startColumn+dir[1]) %mod;
+ result%=mod;
+ }
+
+ return cache[startRow][startColumn][maxMove]= result;
+
+ }
+}
diff --git a/src/main/java/dynamicProgramming/PaintHouses.java b/src/main/java/dynamicProgramming/PaintHouses.java
new file mode 100644
index 0000000..1ea1bc3
--- /dev/null
+++ b/src/main/java/dynamicProgramming/PaintHouses.java
@@ -0,0 +1,27 @@
+package dynamicProgramming;
+
+/**
+ * TODO
+ * https://leetcode.com/problems/paint-house/
+ */
+public class PaintHouses {
+
+ public int minCost(int[][] costs) {
+ if (costs == null || costs.length == 0) return 0;
+ // Assume all costs are positive
+ int n = costs.length; // number of houses
+ int[][] dp = new int[n][3];
+ // Init
+ dp[0][0] = costs[0][0];
+ dp[0][1] = costs[0][1];
+ dp[0][2] = costs[0][2];
+ // DP
+ for (int i = 1; i < n; ++i) {
+ dp[i][0] = Math.min(dp[i - 1][1], dp[i - 1][2]) + costs[i][0];
+ dp[i][1] = Math.min(dp[i - 1][0], dp[i - 1][2]) + costs[i][1];
+ dp[i][2] = Math.min(dp[i - 1][0], dp[i - 1][1]) + costs[i][2];
+ }
+ return Math.min(dp[n - 1][0], Math.min(dp[n - 1][1], dp[n - 1][2]));
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/PerfectSquare.java b/src/main/java/dynamicProgramming/PerfectSquare.java
new file mode 100644
index 0000000..4c5e01d
--- /dev/null
+++ b/src/main/java/dynamicProgramming/PerfectSquare.java
@@ -0,0 +1,86 @@
+package dynamicProgramming;
+
+import java.util.*;
+
+class PerfectSquare {
+ // let's solve by dynamic programming approach
+ // if we take value 13, the number of perfect squares less than
+ // the input at any point is Sqrt(input)=>(sqrt(13)=3, so max it can have answer below)
+ // 3,because 4*4 is 16, so perfect squares below 13 are (1*1, 2*2, 3*3)
+ // 13 can be broken down into
+ // 1/ 4| \ 9 deducting 1^2 leaves with val 12
+ // / | \ deducting 2^2 leaves with val 9
+ // 12 9 4 deducting 3^2 leaves with val 4
+ // /|\ /|\ /|
+ // / | \ 8 5 0 3 0
+ // 11 7 3
+
+ public int numSquaresDp(int n) {
+ int[] ns = new int[n+1];
+
+ for(int i=1;i<=n;i++){
+ int min = i; // initial value is i because it can have i perfect squares(1^2 +1^2+...i)
+ int sqrt = (int)Math.sqrt(i); // because i can have max of sqrt(i) perfect squares
+ for(int j=sqrt;j>0;j--){
+ int result = i - j*j;
+ // the reason to add 1 to the ns[result] is, we take away
+ // a square from 'i' initially (j*j) and check for best answer in the 1-D arr
+ // we add back the 'taken out' square to min value
+ // for e.x if i=13, sqrt is 3, while iterating
+ // we subtract 1*1 from 13 and check for best possible answer for 12 ns[result]
+ // finally we add back the 1*1 as +1 (ns[result]+1)
+ min = Math.min(min, ns[result]+1);
+ }
+ ns[i] = min;
+ System.out.println(Arrays.toString(ns));
+ }
+ return ns[n];
+ }
+
+ public int numSquares(int n){
+ Queue q = new LinkedList<>();
+ Set visited = new HashSet<>();
+ q.offer(0);
+ visited.add(0);
+ int depth = 0;
+ while (!q.isEmpty()) {
+ int size = q.size();
+ depth++;
+ while (size > 0) {
+ int removed = q.poll();
+ for (int i = 1; i * i <= n; i++) {
+ int v = removed + i * i;
+ if (v == n) {
+ return depth;
+ }
+ if (v > n) {
+ break;
+ }
+ if (!visited.contains(v)) {
+ q.offer(v);
+ visited.add(v);
+ }
+ }
+ size--;
+ }
+ }
+ return depth;
+ }
+
+ Integer[]dp= new Integer[10000];
+ public int numSquaresRecur(int n) {
+ if(n<=0) return 0;
+ if(n==1) return 1;
+ if(dp[n]!=null) return dp[n];
+ int count=100000;
+ for(int i=1;i<=Math.sqrt(n);i++){
+ count= Math.min(count, 1+numSquaresRecur(n-i*i));
+ }
+ dp[n]=count;
+ return dp[n];
+ }
+
+ public static void main(String[] args) {
+ new PerfectSquare().numSquaresDp(13);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/StoneGame.java b/src/main/java/dynamicProgramming/StoneGame.java
new file mode 100644
index 0000000..d65c68f
--- /dev/null
+++ b/src/main/java/dynamicProgramming/StoneGame.java
@@ -0,0 +1,78 @@
+package dynamicProgramming;
+
+/**
+ * Pots of Gold
+ * https://leetcode.com/problems/stone-game
+ *
+ * Player A B A
+ *
+ * - pick index i+2
+ * - pick index i+1
+ * - pick index j
+ * - pick index i
+ * - pick index i
+ * - pick index j
+ * - pick index j-1
+ *
+ * - pick index i+2
+ * - pick index i
+ * - pick index j-1
+ * - pick index j
+ * - pick index i
+ * - pick index j-1
+ * - pick index j-2
+ *
+ * For example, stones = [5, 3, 4, 5]
+ *
+ * If A picks left most stone 5, remain stones are [3, 4, 5].
+ *
+ * B with choices to take left most stone 3 or right most stone 5,
+ * and B's best choice is to take right most stone 5 because 5 > 3 & 5 > 4.
+ * Then A has choice to make among remaining stones [3, 4].
+ *
+ * From above decisions, what A can get for next to next round?
+ * If B takes left most stone 3, A's selectable range are [4, 5]
+ * If B takes right most stone 5, A's selectable range are [3, 4]
+ *
+ * And since B make choice to maximum B's score,
+ * choices A can have is not max of([4, 5], [3, 4]) which is [4, 5], but min([4, 5], [3, 4]), which is [3, 4].
+ *
+ * This is a little complicated,
+ * but since B also wants to get maximum score, remaining choices for A is not max but min.
+ *
+ * Use memo for recursion, memo[i][j] means maximum score can get form index i ~j.
+ * The condition for A to win is to make sure either of one condition follows:
+ * memo[0][size-1] > max(memo[1][size-1], memo[0][size-2]).
+ */
+public class StoneGame {
+
+ Integer[][] cache;
+
+ public boolean stoneGame(int[] piles) {
+ cache = new Integer[piles.length + 2][piles.length + 2];
+ int totalSum = 0;
+ for (int pile : piles) {
+ totalSum += pile;
+ }
+
+ return dfsHelper(piles, 0, piles.length - 1) > totalSum / 2;
+ }
+
+ public int dfsHelper(int[] piles, int startIndex, int endIndex) {
+ if (startIndex >= piles.length || endIndex < 0) return 0;
+
+ if (cache[startIndex][endIndex] != null) return cache[startIndex][endIndex];
+
+ int maxStonesPickedFromStart= piles[startIndex] + Math.min(
+ dfsHelper(piles,startIndex+2,endIndex),
+ dfsHelper(piles,startIndex+1,endIndex-1)
+ );
+
+ int maxStonesPickedFromEnd = piles[endIndex] + Math.min(
+ dfsHelper(piles,startIndex,endIndex-2),
+ dfsHelper(piles,startIndex+1,endIndex-1)
+ );
+
+ return Math.max(maxStonesPickedFromEnd,maxStonesPickedFromStart);
+ }
+}
diff --git a/src/main/java/dynamicProgramming/TargetSum.java b/src/main/java/dynamicProgramming/TargetSum.java
new file mode 100644
index 0000000..2a24d86
--- /dev/null
+++ b/src/main/java/dynamicProgramming/TargetSum.java
@@ -0,0 +1,111 @@
+package dynamicProgramming;
+
+/**
+ * https://leetcode.com/problems/target-sum/
+ *
+ * Why 0/1 Knapsack? Our 'Capacity' is the target we want to reach 'S'.
+ * Our 'Items' are the numbers in the input subset and the 'Weights' of the items are the values of the numbers itself.
+ * This question follows 0/1 and not unbounded knapsack because we can use each number ONCE.
+ *
+ * What is the variation? The twist on this problem from standard knapsack is that
+ * we must add ALL items in the subset to our knapsack.
+ * We can reframe the question into adding the positive or negative
+ * value of the current number to our knapsack in order to reach the target capacity 'S'.
+ *
+ * What is the variation? The twist on this problem from standard knapsack is that
+ * we must add ALL items in the subset to our knapsack.
+ * We can reframe the question into adding the positive or negative value of the current number to our knapsack
+ * in order to reach the target capacity 'S'.
+ *
+ * We need 2 base cases. One for when the current state is valid and one for when the current state is invalid.
+ *
+ * Valid: Index is out of bounds AND current sum is equal to target 'S'
+ * Invalid: Index is out of bounds
+ *
+ *
+ * Given nums = [1, 2, 3, 4, 5] and target = 3 then one possible solution is +1-2+3-4+5 = 3
+ * Here positive subset is P = [1, 3, 5] and negative subset is N = [2, 4]
+ *
+ * Then let's see how this can be converted to a subset sum problem:
+ *
+ * sum(P) - sum(N) = target
+ * sum(P) + sum(N) + sum(P) - sum(N) = target + sum(P) + sum(N)
+ * 2 * sum(P) = target + sum(nums)
+ */
+public class TargetSum {
+ Integer[][] cache;
+
+ public int findTargetSumWays(int[] nums, int target) {
+ int sum = 0;
+ for (int i : nums) sum += i;
+ cache = new Integer[1001][2 * sum + 1];
+
+ // the reason we send target+sum and sum instead of target and 0 is
+ // sum-nums[index] will produce negative values which will throw index out of bound exception at cache[index][sum]
+ return recursionHelper(nums, target + sum, 0, sum);
+ }
+
+ public int recursionHelper(int[] nums, int target, int index, int sum) {
+
+ if (index >= nums.length) {
+ return target == sum ? 1 : 0;
+ }
+
+ if (cache[index][sum] != null) return cache[index][sum];
+
+ int left = recursionHelper(nums, target, index + 1, sum + nums[index]);
+
+ int right = recursionHelper(nums, target, index + 1, sum - nums[index]);
+
+ return cache[index][sum] = left + right;
+ }
+
+ /** solution 2: DP (0/1 knapsack) - Time: O(n^2), Space: O(n^2) Thanks @jerry */
+ /**
+ * sub-problem: dp[i][j] represents number of possible ways to reach sum j by using first ith items
+ * base case: dp[0][sum], position sum represents sum 0
+ * recurrence relation:
+ * dp[i][j] += dp[i - 1][j + nums[i - 1]] if j + nums[i - 1] <= sum * 2
+ * dp[i][j] += dp[i - 1][j - nums[i - 1]] if j - nums[i - 1] >= 0
+ *
+ * explanation: if j + nums[i - 1] or j - nums[i - 1] is in correct range, we can use the number nums[i - 1]
+ * to generate next state of dp array
+ */
+ public static int findTargetSumWaysBottomUp(int[] nums, int S) {
+ if (nums.length == 0) {
+ return 0;
+ }
+
+ int sum = 0;
+ for (int num : nums) {
+ sum += num;
+ }
+
+ // corner case: when S is out of range [-sum, sum]
+ if (S < -sum || S > sum) {
+ return 0;
+ }
+
+ int[][] dp = new int[nums.length + 1][sum * 2 + 1];
+ dp[0][sum] = 1;
+ int leftBound = 0;
+ int rightBound = sum * 2;
+ for (int i = 1; i <= nums.length; i++) {
+ for (int j = leftBound; j < rightBound + 1; j++) {
+ // try all possible sum of (previous sum j + current number nums[i - 1]) and all possible difference of
+ // (previous sum j - current number nums[i - 1])
+ if (j + nums[i - 1] <= rightBound) {
+ dp[i][j] += dp[i - 1][j + nums[i - 1]];
+ }
+ if (j - nums[i - 1] >= leftBound) {
+ dp[i][j] += dp[i - 1][j - nums[i - 1]];
+ }
+ }
+ }
+ return dp[nums.length][sum + S];
+ }
+
+ public static void main(String[] args) {
+ System.out.println(findTargetSumWaysBottomUp(new int[]{1, 1, 1, 1, 1}, 3));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/TriangleSum.java b/src/main/java/dynamicProgramming/TriangleSum.java
new file mode 100644
index 0000000..65dd427
--- /dev/null
+++ b/src/main/java/dynamicProgramming/TriangleSum.java
@@ -0,0 +1,64 @@
+package dynamicProgramming;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * https://leetcode.com/problems/triangle/
+ */
+public class TriangleSum {
+ static Integer[][] cache = null;
+
+ public static int minimumTotal(List> triangle) {
+ cache = new Integer[triangle.size()][triangle.size()];
+
+ return recursionUtil(triangle, 0, 0);
+ }
+
+ public static int recursionUtil(List> triangle, int triangleIndex, int subIndex) {
+ if (triangleIndex >= triangle.size()) return 0;
+
+ if (cache[triangleIndex][subIndex] != null) return cache[triangleIndex][subIndex];
+
+ // recursively take from next rom same column
+ int left = recursionUtil(triangle, triangleIndex + 1, subIndex);
+
+ // recursively take for next row, next column
+ int right = recursionUtil(triangle, triangleIndex + 1, subIndex + 1);
+
+ cache[triangleIndex][subIndex] = Math.min(left, right) + triangle.get(triangleIndex).get(subIndex);
+
+ return cache[triangleIndex][subIndex];
+ }
+
+ public static int minimumTotalBottomUp(List> triangle) {
+
+ int[][] dp = new int[triangle.size()][triangle.size()];
+ // the commented code is to optimise the O(N^2) space
+ // int[]dp = new int[triangle.size()];
+ // int[]dp1 = new int[triangle.size()];
+
+ //Remember base case is just returning leaf nodes
+ for (int i = 0; i < triangle.size(); i++) {
+ dp[triangle.size() - 1][i] = triangle.get(triangle.size() - 1).get(i);
+ }
+
+ for (int row = triangle.size() - 2; row >= 0; row--) {
+ for (int pos = 0; pos < triangle.get(row).size(); pos++) {
+ //dp1[pos] = triangle.get(row).get(pos) + Math.min(dp[pos+1], dp[pos]);
+ dp[row][pos] = triangle.get(row).get(pos) + Math.min(dp[row + 1][pos], dp[row + 1][pos + 1]);
+ }
+ //dp = dp1;
+ }
+
+ return dp[0][0];
+ }
+
+ public static void main(String[] args) {
+ List> triangle = Arrays.stream(new Integer[][]{{2}, {3, 4}, {6, 5, 7}, {4, 1, 8, 3}})
+ .map(Arrays::asList)
+ .collect(Collectors.toList());
+ minimumTotalBottomUp(triangle);
+ }
+}
diff --git a/src/main/java/dynamicProgramming/TwoKeysKeyBoard.java b/src/main/java/dynamicProgramming/TwoKeysKeyBoard.java
new file mode 100644
index 0000000..7a0b434
--- /dev/null
+++ b/src/main/java/dynamicProgramming/TwoKeysKeyBoard.java
@@ -0,0 +1,49 @@
+package dynamicProgramming;
+
+public class TwoKeysKeyBoard {
+
+ /**
+ * the idea is if i is even(i%2), go to the i/2 position and add 2 (1- for copy and 1- for paste)
+ * if i is odd, we need to check what other odd is factor of i, initialise j and iterate till sqrt(i)
+ * if we find i%j==0 then we go to i%j position and add 1-for copy and j-1 for paste
+ * for e.x if i=9 we find j=3 (i%3==0), we go to i/j (3rd position which has 'AAA') and copy and paste it 2 times
+ * i=3(AAA), copy and paste 2 times (AAA-AAA-AAA) we get 9 items
+ *
+ */
+ public static int minSteps(int n) {
+ int[] dp = new int[n+1];
+ dp[1]=0;
+ for(int i=2;i<=n;i++){
+ dp[i] = i; // this is for prime numbers
+ if(i%2==0){
+ dp[i] = dp[i/2]+1+1; // 1 for copy + 1 for paste
+ }else{
+ for(int j=2;j<=Math.sqrt(i);j++){
+ if(i%j==0){
+ dp[i] = Math.min(dp[i], dp[i/j] + 1 + j-1); //1 for copy and (j-1) for paste
+ }
+ }
+ }
+
+ }
+ return dp[n];
+ }
+
+ int[] dp = new int[1001];
+ public int minStepRecurs(int n) {
+ if(n==1) return 0;
+ if(dp[n]!=0) return dp[n];
+ int min=n;
+ for(int i=2;i<=Math.sqrt(n);i++){
+ if(n%i==0){
+ min = Math.min(min, minStepRecurs(n/i) + 1 + i-1); //1 for copy and (i-1) for paste
+ }
+ }
+ dp[n] = min;
+ return min;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(minSteps(9));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/UniqueCoinChange.java b/src/main/java/dynamicProgramming/UniqueCoinChange.java
new file mode 100644
index 0000000..aefecff
--- /dev/null
+++ b/src/main/java/dynamicProgramming/UniqueCoinChange.java
@@ -0,0 +1,36 @@
+package dynamicProgramming;
+
+
+/**
+ * https://leetcode.com/problems/coin-change
+ */
+public class UniqueCoinChange {
+
+ public int changeSpaceOptimised(int amount, int[] coins) {
+ int[] combi = new int[amount + 1];
+ combi[0] = 1;
+ for (int coin : coins) {
+ for (int j = 1; j <= amount; j++) {
+ if (j - coin >= 0)
+ combi[j]+= combi[j - coin];
+ }
+ }
+ for (int a : combi)
+ System.out.print(a + " ");
+ return combi[amount];
+ }
+
+ public int changeRecursion(int amount, int[] coins) {
+ Integer[][] dp = new Integer[amount+1][coins.length+1];
+ return recursionHelper(amount,0,coins,dp);
+ }
+
+ public int recursionHelper(int amount, int idx, int[] coins,Integer[][] dp){
+ if(amount==0) return 1;
+ if(amount<=0 || idx>=coins.length) return 0;
+ if(dp[amount][idx]!=null) return dp[amount][idx];
+
+ return dp[amount][idx]=recursionHelper(amount-coins[idx],idx,coins,dp)+recursionHelper(amount,idx+1,coins,dp);
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/fibonacci/DecodeWays.java b/src/main/java/dynamicProgramming/fibonacci/DecodeWays.java
new file mode 100644
index 0000000..7aa87b1
--- /dev/null
+++ b/src/main/java/dynamicProgramming/fibonacci/DecodeWays.java
@@ -0,0 +1,83 @@
+package dynamicProgramming.fibonacci;
+
+
+/**
+ Case 1 : Pick single element, so in this we pick current and call for index + 1.
+ note : In case of single pick, element should not be '0' as it is invalid
+
+ -> ways = decode(s, idx+1, n)
+ : elements in range [1,9] is covered here in this case
+
+ Case 2 : Pick couple, so that we can get elements in range [10, 26] .
+ Catch here is that we need to check and validate values so that we do not exceed the range.
+
+ */
+public class DecodeWays {
+
+ public int numDecodings(String s) {
+ if (s == null || s.isEmpty()) {
+ return 0;
+ }
+ int n = s.length();
+ int[] dp = new int[n + 1];
+ dp[0] = 1; // an empty string can only be decoded as an empty string
+ dp[1] = s.charAt(0) != '0' ? 1 : 0; // If current element is 0, we simply return 0 as it is not possible to get a character using 0.
+ for (int i = 2; i <= n; i++) {
+ int first = Integer.parseInt(s.substring(i - 1, i));
+ int second = Integer.parseInt(s.substring(i - 2, i));
+ if (first >= 1 && first <= 9) {
+ dp[i] += dp[i - 1];
+ }
+ if (second >= 10 && second <= 26) {
+ dp[i] += dp[i - 2];
+ }
+ }
+ return dp[n];
+ }
+
+ public int numDecodings1(String s) {
+ if (s == null || s.isEmpty()) return 0;
+ Integer[] cache = new Integer[s.length() + 1];
+ return helperFn(s, 0, cache);
+ }
+
+ public int helperFn(String s, int index, Integer[] cache) {
+ //When we reach the end of the string this means that we have found a possible way to decode.
+ //Thus, this will contribute to answer and return 1.
+ if (index >= s.length()) return 1;
+
+ if (cache[index] != null) return cache[index];
+ int total = 0;
+ if (index + 1 <= s.length()) {
+ String temp1 = s.substring(index, index + 1);
+ if (valid(temp1)) {
+ total += helperFn(s, index + 1, cache);
+ }
+ }
+
+ if (index + 2 <= s.length()) {
+ String temp2 = s.substring(index, index + 2);
+ if (valid(temp2)) {
+ total += helperFn(s, index + 2, cache);
+ }
+ }
+
+ cache[index] = total;
+ return cache[index];
+
+ }
+
+ public boolean valid(String s1) {
+ if (s1.isEmpty()) return false;
+ if (s1.charAt(0) == '0') return false; //If current element is 0, we simply return 0 as it is not possible to get a character using 0.
+
+ int val = Integer.parseInt(s1);
+
+ return val >= 1 && val <= 26;
+ }
+
+ public static void main(String[] args) {
+ DecodeWays decode = new DecodeWays();
+ System.out.println(decode.numDecodings("1210"));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/fibonacci/DiceThrow.java b/src/main/java/dynamicProgramming/fibonacci/DiceThrow.java
new file mode 100644
index 0000000..b176233
--- /dev/null
+++ b/src/main/java/dynamicProgramming/fibonacci/DiceThrow.java
@@ -0,0 +1,38 @@
+package dynamicProgramming.fibonacci;
+
+/**
+ * Time Complexity: O(m * n * x)
+ * https://leetcode.com/problems/number-of-dice-rolls-with-target-sum
+ */
+class DiceThrow {
+ // f-> faces
+ // d->dices
+ // target->sum
+ static Integer[][] cache = new Integer[31][1001];
+
+ public static int numRollsToTarget(int d, int f, int target) {
+ if (d <= 0 || target < 0) return target == 0 ? 1 : 0;
+ if (cache[d][target] != null) return cache[d][target];
+ int ways = 0;
+ for (int i = 1; i <= f; i++) {
+ ways += numRollsToTarget(d - 1, f, target - i);
+ ways %= 1000000007;
+ }
+
+ return cache[d][target] = ways;
+ }
+
+ public int numRollsToTargetBottomUp(int d, int f, int target) {
+ int[][] dp = new int[d + 1][target + 1];
+ dp[0][0] = 1;
+ for (int i = 1; i <= d; i++)
+ for (int j = 1; j <= target; j++)
+ for (int k = 1; k <= f; k++)
+ dp[i][j] = (dp[i][j] + (k <= j ? dp[i - 1][j - k] : 0)) % 1000000007;
+ return dp[d][target];
+ }
+
+ public static void main(String[] args) {
+ System.out.println(numRollsToTarget(6, 3, 6));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/fibonacci/FibonacciStaircaseWaysToCoverDist.java b/src/main/java/dynamicProgramming/fibonacci/FibonacciStaircaseWaysToCoverDist.java
new file mode 100644
index 0000000..09a0502
--- /dev/null
+++ b/src/main/java/dynamicProgramming/fibonacci/FibonacciStaircaseWaysToCoverDist.java
@@ -0,0 +1,110 @@
+package dynamicProgramming.fibonacci;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+public class FibonacciStaircaseWaysToCoverDist {
+
+ public int fibonacciSeriesRecursive(int n) {
+ if (n == 1)
+ return 2;
+ if (n == 2)
+ return 3;
+ return fibonacciSeriesRecursive(n - 1) + fibonacciSeriesRecursive(n - 2);
+ }
+
+ public static void main(String args[]) {
+ FibonacciStaircaseWaysToCoverDist fs = new FibonacciStaircaseWaysToCoverDist();
+ System.out.println(fs.fibonacciSeries(4));
+ System.out.println(fs.fibonacciSeriesRecursive(3));
+ }
+
+ public int fibonacciSeries(int n) {
+ int n1 = 0;
+ int n2 = 1;
+ int sum;
+
+ if (n == n1 || n == n2) {
+ return n;
+ }
+
+ for (int i = 1; i <= n; i++) {
+ sum = n1 + n2;
+ n1 = n2;
+ n2 = sum;
+ }
+ return n2;
+ }
+
+
+ public int climbStairsBottomUp(int n) {
+ int[] dp = new int[n + 1];
+ dp[0] = 0;
+ dp[1] = 1;
+ dp[2] = 2;
+ for (int stair = 3; stair <= n; ++stair) {
+ dp[stair] += dp[stair - 1] + dp[stair - 2];
+ }
+
+ return dp[n];
+ }
+
+ public int climbStairs(int N) {
+ int[] cache = new int[N + 1];
+ Arrays.fill(cache, -1);
+ return fibUtil(N, 0, cache);
+ }
+
+ public int fibUtil(int N, int start, int[] cache) {
+ if (start > N) return 0;
+
+ if (N == start) return 1;
+
+ if (cache[start] != -1) return cache[start];
+
+ cache[start] = fibUtil(N, start + 1, cache) + fibUtil(N, start + 2, cache);
+
+ return cache[start];
+ }
+
+
+ public int minCostClimbingStairs(int[] cost) {
+ if (cost.length == 2) return Math.min(cost[0], cost[1]);
+ int[] dp = new int[cost.length + 1];
+ dp[0] = cost[0];
+ dp[1] = cost[1];
+
+ for (int i = 2; i < cost.length; i++) {
+ dp[i] = Math.min(dp[i - 1], dp[i - 2]) + cost[i];
+ }
+
+ return Math.min(dp[cost.length - 1], dp[cost.length - 2]);
+ }
+
+ private HashMap memo = new HashMap<>();
+
+ public int minCostClimbingStairsRecursion(int[] cost) {
+ return minimumCost(cost.length, cost);
+ }
+
+ private int minimumCost(int i, int[] cost) {
+ // Base case, we are allowed to start at either step 0 or step 1
+ if (i <= 1) {
+ return 0;
+ }
+
+ // Check if we have already calculated minimumCost(i)
+ if (memo.containsKey(i)) {
+ return memo.get(i);
+ }
+
+ // If not, cache the result in our hash map and return it
+ int downOne = cost[i - 1] + minimumCost(i - 1, cost);
+ int downTwo = cost[i - 2] + minimumCost(i - 2, cost);
+ memo.put(i, Math.min(downOne, downTwo));
+ return memo.get(i);
+ }
+
+}
+
+
diff --git a/src/main/java/dynamicProgramming/lcs/BitonicSequence.java b/src/main/java/dynamicProgramming/lcs/BitonicSequence.java
new file mode 100644
index 0000000..b0a0959
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/BitonicSequence.java
@@ -0,0 +1,70 @@
+package dynamicProgramming.lcs;
+
+/**
+ * https://leetcode.com/problems/minimum-number-of-removals-to-make-mountain-array/
+ *
+ * tricky LIS
+ */
+public class BitonicSequence {
+ /**
+ * Concept: We need to find the maximum number of elements of the array that can be
+ * involved in a mountain array. We know, that a mountain array contains a peak element
+ * and there is an increasing subsequence in the left of the peak and a decreasing subsequence in the right.
+ * So, we need to find out the element(peak), for which the total number of elements from the
+ * original array involved in the left increasing subsequence and the right decreasing
+ * subsequence, in maximum. This will create a mountain array with the peak element.
+ * Then, we can delete the rest of the elements of the array not involved in this mountain array.
+ */
+ public int longestSequence(int arr[]) {
+ int[] lis = new int[arr.length];
+ int[] lds = new int[arr.length];
+ for (int i = 0; i < arr.length; i++) {
+ lis[i] = 1;
+ lds[i] = 1;
+ }
+ for (int i = 1; i < arr.length; i++) {
+ for (int j = 0; j < i; j++) {
+ if (arr[i] > arr[j]) {
+ lis[i] = Math.max(lis[i], lis[j] + 1);
+ }
+ }
+ }
+
+ for (int i = arr.length - 2; i >= 0; i--) {
+ for (int j = arr.length - 1; j > i; j--) {
+ if (arr[i] > arr[j]) {
+ lds[i] = Math.max(lds[i], lds[j] + 1);
+ }
+ }
+ }
+ // because that middle element is common in both sequence .. for example,
+ // increasing subsequence 2,8,20 .. decreasing one 20,13,14 .. each of them has
+ // length 3 .. but bitonic subsequence 2,8,20,13,14 .. length= 3+3-1=5
+ int max = 0;
+ for (int i = 0; i < arr.length; i++) {
+ /*
+ If the below conditional statement is not given, then strictly increasing or strictly
+ decreasing sequences will also be considered. It will hence fail in,
+ Test case: [10, 9, 8, 7, 6, 5, 4, 5, 4].
+ ---Thanks to @chejianchao for suggesting the test case.
+ We need to make sure both the LIS on the left and right, ending at index i,
+ has length > 1.
+ */
+ int max1 = lis[i] + lds[i] - 1; //Peak is counted twice in lis[] and lsd[] so -1
+ System.out.print(max1 + " ");
+ if (max < max1) {
+ max = max1;
+ }
+ }
+
+ return max;
+ }
+
+ public static void main(String args[]) {
+ BitonicSequence bs = new BitonicSequence();
+ int[] arr = {1, 4, 3, 7, 2, 1, 8, 11, 13, 0};
+ int r = bs.longestSequence(arr);
+ System.out.println(r);
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/lcs/DeleteAndEarn.java b/src/main/java/dynamicProgramming/lcs/DeleteAndEarn.java
new file mode 100644
index 0000000..a0f4123
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/DeleteAndEarn.java
@@ -0,0 +1,70 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+
+public class DeleteAndEarn {
+
+ public int deleteAndEarn(int[] nums) {
+ // if we sort the array, we do not need to delete elements smaller than nums[idx] (ie nums[idx] - 1) because they are already computed
+ // and saved in memo, we only need to delete nums[idx] + 1 and we can do this simply by skipping them since the array is sorted
+ Arrays.sort(nums);
+ Integer[] dp = new Integer[nums.length];
+ return recursionUtil(nums, 0, dp);
+ }
+
+ private int recursionUtil(int[] nums, int idx, Integer[] dp) {
+ // if we reached the end of the array, we can not earn anymore, return 0
+ if (idx == nums.length)
+ return 0;
+
+ if (dp[idx] != null) return dp[idx];
+ // delete and earn this element
+ int earned = nums[idx];
+ int skip = idx + 1;
+
+ // simply add all similar values of nums[idx] to earned at once
+ while (skip < nums.length && nums[skip] == nums[idx]) {
+ earned += nums[idx];
+ skip++;
+ }
+
+ // skip all elements = nums[idx] + 1
+ // this is instead of deleting the elements = nums[idx] + 1
+ // which does not alter the array and make the solution work
+ while (skip < nums.length && nums[skip] == nums[idx] + 1)
+ skip++;
+
+ // recurse
+ earned += recursionUtil(nums, skip, dp);
+
+ // skip deleting and earning this element
+ int skipped = recursionUtil(nums, idx + 1, dp);
+
+ // return the max of the 2 values
+ dp[idx] = Math.max(earned, skipped);
+
+
+ return dp[idx];
+ }
+
+ /**
+ * for numbers from [1 - 10000], each has a total sum sums[i]; if you earn sums[i], you cannot earn sums[i-1] and sums[i+1]
+ * kind of like house robbing. you cannot rob 2 connected houses.
+ */
+
+ public int deleteAndEarnBottomUp(int[] nums) {
+ int n = 10001;
+ int[] values = new int[n];
+ for (int num : nums)
+ values[num] += num;
+
+ int take = 0, skip = 0;
+ for (final int value : values) {
+
+ final int temp = Math.max(skip + value, take);
+ skip = take;
+ take = temp;
+ }
+ return take;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/EditDistance.java b/src/main/java/dynamicProgramming/lcs/EditDistance.java
new file mode 100644
index 0000000..a84ee9b
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/EditDistance.java
@@ -0,0 +1,135 @@
+package dynamicProgramming.lcs;
+
+/**
+ *
+ * @author Tushar Roy
+ *
+ * Given two strings how many minimum edits(update, delete or add) is
+ * needed to convert one string to another
+ *
+ * Time complexity is O(m*n) Space complexity is O(m*n)
+ *
+ * References:
+ * http://www.geeksforgeeks.org/dynamic-programming-set-5-edit-distance/
+ * https://en.wikipedia.org/wiki/Edit_distance
+ */
+public class EditDistance {
+
+
+ /**
+ * Uses bottom up DP to find the edit distance
+ */
+ public int dynamicEditDistance(char[] str1, char[] str2) {
+ int temp[][] = new int[str1.length + 1][str2.length + 1];
+
+ for (int i = 0; i < temp[0].length; i++) {
+ temp[0][i] = i; // it's number of edits to make top row empty, remember dp[0][0]="" empty char
+ }
+
+ for (int i = 0; i < temp.length; i++) {
+ temp[i][0] = i; // it's number of edits to make empty char into first col values, remember dp[0][0]="" empty char
+ }
+
+ for (int i = 1; i <= str1.length; i++) {
+ for (int j = 1; j <= str2.length; j++) {
+ if (str1[i - 1] == str2[j - 1]) {
+ temp[i][j] = temp[i - 1][j - 1];
+ } else {
+ temp[i][j] = 1 + min(temp[i - 1][j - 1], temp[i - 1][j], temp[i][j - 1]);
+ }
+ }
+ }
+ printActualEdits(temp, str1, str2);
+ return temp[str1.length][str2.length];
+
+ }
+
+ /**
+ * Prints the actual edits which needs to be done.
+ */
+ public void printActualEdits(int T[][], char[] str1, char[] str2) {
+ int i = T.length - 1;
+ int j = T[0].length - 1;
+ while (true) {
+ if (i == 0 || j == 0) {
+ break;
+ }
+ if (str1[i - 1] == str2[j - 1]) {
+ i = i - 1;
+ j = j - 1;
+ } else if (T[i][j] == T[i - 1][j - 1] + 1) {
+ System.out.println("Edit " + str2[j - 1] + " in string2 to " + str1[i - 1] + " in string1");
+ i = i - 1;
+ j = j - 1;
+ } else if (T[i][j] == T[i - 1][j] + 1) {
+ System.out.println("Delete in string1 " + str1[i - 1]);
+ i = i - 1;
+ } else if (T[i][j] == T[i][j - 1] + 1) {
+ System.out.println("Delete in string2 " + str2[j - 1]);
+ j = j - 1;
+ } else {
+ throw new IllegalArgumentException("Some wrong with given data");
+ }
+ }
+ }
+
+ public int minDistance(String word1, String word2) {
+ if(word1==null) return word2.length();
+ if(word2==null) return word1.length();
+
+ int[][] dp= new int[word1.length()+1][word2.length()+1];
+
+ for(int i = 0;i<=word1.length();i++) dp[i][0] = i;
+ for(int j = 0;j<=word2.length();j++) dp[0][j] = j;
+
+ for(int i=1;i<=word1.length();i++){
+ for(int j=1; j<= word2.length(); j++){
+ if(word1.charAt(i-1)==word2.charAt(j-1)){
+ dp[i][j]=dp[i-1][j-1];
+ }else{
+ dp[i][j]= 1+Math.min(dp[i-1][j-1], Math.min(dp[i-1][j], dp[i][j-1]));
+ }
+ }
+ }
+
+ return dp[word1.length()][word2.length()];
+ }
+
+ Integer[][] cache;
+ public int minDistanceTopDown(String word1, String word2) {
+ cache= new Integer[word1.length()][word2.length()];
+ return recursionHelper(word1,word2,0,0);
+ }
+
+ public int recursionHelper(String word1, String word2, int idx1, int idx2){
+ if(idx1>=word1.length()) return word2.length()-idx2;
+ if(idx2>=word2.length()) return word1.length()-idx1;
+
+ if(cache[idx1][idx2]!=null) return cache[idx1][idx2];
+
+ int result=0;
+ if(word1.charAt(idx1)==word2.charAt(idx2)){
+ result+= recursionHelper(word1,word2,idx1+1,idx2+1);
+ }else{
+ result+= 1+ Math.min(recursionHelper(word1,word2,idx1+1,idx2+1),
+ Math.min(recursionHelper(word1,word2,idx1+1,idx2),recursionHelper(word1,word2,idx1,idx2+1)));
+ }
+
+ return cache[idx1][idx2]=result;
+ }
+ private int min(int a, int b, int c) {
+ int l = Math.min(a, b);
+ return Math.min(l, c);
+ }
+
+ public static void main(String args[]) {
+ String str1 = "abcd";
+ String str2 = "bcad";
+ EditDistance editDistance = new EditDistance();
+ int result = editDistance.dynamicEditDistance(str1.toCharArray(), str2.toCharArray());
+ System.out.print(result);
+ }
+
+}
+
+
diff --git a/src/main/java/dynamicProgramming/lcs/LongestCommonSubsequence.java b/src/main/java/dynamicProgramming/lcs/LongestCommonSubsequence.java
new file mode 100644
index 0000000..302a9ab
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/LongestCommonSubsequence.java
@@ -0,0 +1,72 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+
+public class LongestCommonSubsequence {
+
+ // mistake i normally would assume is dp[0][0]=1, but actually it's not
+
+ public static void main(String[] args) {
+ String str1 = "ABCD";
+ String str2 = "AEDB";
+
+ System.out.println(longestCommonSubSeqPrint(str1, str2));
+
+ }
+
+ public static int longestCommonSubsequence(String text1, String text2) {
+ if (text1 == null || text2 == null) return 0;
+
+ int[][] dp = new int[text1.length() + 1][text2.length() + 1];
+
+ for (int i = 1; i <= text1.length(); i++) {
+ for (int j = 1; j <= text2.length(); j++) {
+ if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
+ dp[i][j] = 1 + dp[i - 1][j - 1]; // previously matched characters
+ } else {
+ dp[i][j] = Math.max(dp[i][j - 1], dp[i - 1][j]);
+ }
+ }
+ }
+
+ return dp[text1.length()][text2.length()];
+ }
+
+ Integer[][] cache;
+
+ public int longestCommonSubsequenceTopDown(String text1, String text2) {
+ cache = new Integer[text1.length() + 1][text2.length() + 1];
+ return recursionHelper(text1, text2, text1.length() - 1, text2.length() - 1);
+ }
+
+ public int recursionHelper(String text1, String text2, int index1, int index2) {
+ if (index1 < 0 || index2 < 0) return 0;
+ if (cache[index1][index2] != null) return cache[index1][index2];
+
+ if (text1.charAt(index1) == text2.charAt(index2)) {
+ return cache[index1][index2] = 1 + recursionHelper(text1, text2, index1 - 1, index2 - 1);
+ } else {
+ return cache[index1][index2] = Math.max(recursionHelper(text1, text2, index1 - 1, index2),recursionHelper(text1, text2, index1, index2 - 1));
+ }
+ }
+
+ private static String longestCommonSubSeqPrint(String str1, String str2) {
+ String[][] dp = new String[str1.length() + 1][str2.length() + 1];
+ for (String[] strings : dp) {
+ Arrays.fill(strings, "");
+ }
+ for (int i = 1; i <= str1.length(); i++) {
+ for (int j = 1; j <= str2.length(); j++) {
+ if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
+ dp[i][j] = dp[i - 1][j - 1] + str1.charAt(i - 1);
+ } else {
+ dp[i][j] = dp[i - 1][j].length() > dp[i][j - 1].length() ? dp[i - 1][j] : dp[i][j - 1];
+ }
+ }
+ }
+ return dp[str1.length()][str2.length()];
+ }
+
+}
+
+
diff --git a/src/main/java/dynamicProgramming/lcs/LongestCommonSubstring.java b/src/main/java/dynamicProgramming/lcs/LongestCommonSubstring.java
new file mode 100644
index 0000000..245c1bd
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/LongestCommonSubstring.java
@@ -0,0 +1,37 @@
+package dynamicProgramming.lcs;
+
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * http://en.wikipedia.org/wiki/Longest_common_substring_problem
+ */
+public class LongestCommonSubstring {
+
+ public int longestCommonSubstring(char str1[], char str2[]) {
+ int T[][] = new int[str1.length + 1][str2.length + 1];
+
+ int max = 0;
+ for (int i = 1; i <= str1.length; i++) {
+ for (int j = 1; j <= str2.length; j++) {
+ if (str1[i - 1] == str2[j - 1]) {
+ T[i][j] = T[i - 1][j - 1] + 1;
+ if (max < T[i][j]) {
+ max = T[i][j];
+ }
+ }
+ }
+ }
+
+ return max;
+ }
+
+ public static void main(String args[]) {
+ LongestCommonSubstring lcs = new LongestCommonSubstring();
+ char str1[] = "abcdef".toCharArray();
+ char str2[] = "zcdemf".toCharArray();
+ System.out.println(lcs.longestCommonSubstring(str1, str2));
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/lcs/LongestIncreasingSubsequence.java b/src/main/java/dynamicProgramming/lcs/LongestIncreasingSubsequence.java
new file mode 100644
index 0000000..d841989
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/LongestIncreasingSubsequence.java
@@ -0,0 +1,133 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+
+/**
+ * Solve the LIS subproblem for each snippet of the array ending between 1, 2,
+ * 3, ... and so on until nums.length - 1 (inclusive)
+ *
+ * Ex:
+ *
+ * [-2, 1, 2, 3]
+ *
+ * [-2] from index 0 to index 0 [-2, 1] from index 0 to index 1 [-2, 1, 2] from
+ * index 0 to index 2 [-2, 1, 2, 3] from index 0 to index 3
+ *
+ * Our answer is the maximum LNDS found between all subproblems we solve along
+ * the way.
+ *
+ * Time complexity is O(n^2).
+ */
+public class LongestIncreasingSubsequence {
+
+ public static void main(String[] args) {
+ int[] nums = {10, 22, 9, 33, 21, 50, 41, 60, 80};
+ lisLength(nums);
+ }
+
+ private static void lisLength(int[] nums) {
+ int[] result = new int[nums.length];
+ Arrays.fill(result, 1);
+ int maximumSoFar = 1;
+ for (int i = 1; i < nums.length; i++) {
+ for (int j = 0; j < i; j++) {
+ if (nums[i] > nums[j]) {
+ result[i] = Math.max(result[i], result[j] + 1);
+ }
+ }
+ maximumSoFar = Math.max(maximumSoFar, result[i]);
+ }
+ System.out.println(Arrays.toString(result));
+ System.out.println(maximumSoFar);
+ }
+
+ public int lengthOfLISBottomUp(int[] nums) {
+ //there were two chaning variable in recursive solution curr and prev
+ //so we need a 2d matrix
+ //length decision:-prev will go max upto nums.length so will take nums.length+1
+ // curr will go max upto nums.length-1 so will take nums.length
+ //for initialization of dp matrix initialize it with -1
+
+ int[][] dp = new int[nums.length + 1][nums.length];
+ for (int[] x : dp) {
+ Arrays.fill(x, -1);
+ }
+ return solve(nums, -1, 0, dp);
+ }
+
+ public int solve(int[] nums, int prevIndex, int curr, int[][] dp) {
+ if (curr == nums.length) {
+ return 0;
+ }
+
+ if (dp[prevIndex + 1][curr] != -1) {
+ return dp[prevIndex + 1][curr];
+ }
+
+ if (prevIndex < 0 || nums[curr] > nums[prevIndex]) {
+ dp[prevIndex + 1][curr] = Math.max(1 + solve(nums, curr, curr + 1, dp),
+ solve(nums, prevIndex, curr + 1, dp));
+ } else {
+ dp[prevIndex + 1][curr] = solve(nums, prevIndex, curr + 1, dp);
+ }
+ return dp[prevIndex + 1][curr];
+ }
+
+ /**
+ * https://www.youtube.com/watch?v=qW1O1a40-No&ab_channel=AryanMittal
+ *
+ * Idea is to prepare a result array, the result array will be sorted obviously because, we are looking for
+ * LIS.
+ * case i) if current element arr[i] is greater that result[result.length-1] append to result
+ * case ii) else we need to look for a suitable position in the result arr for that element arr[i]
+ * which has arr[i-1]>=arr[i]=
+ * arr[]= {2,5,3,7,11,8,10,13,6}
+ * result[]={}
+ * when i=2(arr[i]=3)
+ * result=[2,5]
+ * we need to see a position for 3 to accommodate, do a binary search in [2,5], we'll get index 1
+ * so we modify the result = [2,3] *Note the length is not changed
+ *
+ * when i=6 (arr[i]=8)
+ * result=[2,3,7,11] we need to check for a position, do a binary search in [2,3,6,7], we'll get index 3
+ * result=[2,3,7,8]
+ *
+ * when i=8(arr[i]=6)
+ * result=[2,3,7,8,10,13] or [2,5,7,8,10,13] do a binary search , we'll get index 2
+ * result=[2,3,6,8,10,13] at this point we are not bothered about the correctness of result
+ * all we need is the length
+ */
+ public static int lengthOfLIS(int[] nums) {
+ if (nums == null || nums.length == 0)
+ return 0;
+
+ int n = nums.length, len = 0;
+ int[] increasingSequence = new int[n];
+ increasingSequence[len++] = nums[0];
+ for (int i = 1; i < n; i++) {
+ if (nums[i] > increasingSequence[len - 1])
+ increasingSequence[len++] = nums[i];
+ else {
+ int position = findPositionToReplace(increasingSequence, 0, len - 1, nums[i]);
+ increasingSequence[position] = nums[i];
+ }
+ }
+ return len;
+ }
+
+ public static int findPositionToReplace(int[] a, int low, int high, int x) {
+ int mid;
+ while (low < high) {
+ mid = low + (high - low) / 2;
+ if (a[mid] < x) {
+ low = mid + 1;
+ } else {
+ high = mid;
+ }
+ }
+ return low;
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/lcs/LongestStringChain.java b/src/main/java/dynamicProgramming/lcs/LongestStringChain.java
new file mode 100644
index 0000000..c46305a
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/LongestStringChain.java
@@ -0,0 +1,89 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * https://leetcode.com/problems/longest-string-chain/
+ */
+public class LongestStringChain {
+
+ /**
+ * Algorithm
+ * Initialize a set (wordsPresent) and add all the words in the list to the set. This set will be used to check if a word is present in the list.
+ * Initialize a map (memo) having key type as String and value type as Integer. This map will store the length of the longest possible word sequence where the key is the last word in the sequence.
+ * Iterate over the list. For each word in the list perform a depth-first search.
+ * In the DFS, consider the current word (currentWord) as the last word in the word sequence.
+ * If currentWord was encountered previously we just return its corresponding value in the map memo.
+ * Initialize maxLength to 1.
+ * Iterate over the entire length of the currentWord.
+ * Create all possible words (newWord) by taking out one character at a time.
+ * If newWord is present in the set perform a DFS with this word and store the intermediate result in a variable currentLength.
+ * Update the maxLength so that it contains the length of the longest sequence possible where the currentWord is the end word.
+ * Set the maxLength as the value for currentWord (key) in the map.
+ * Return maxLength.
+ */
+ private int dfs(Set words, Map memo, String currentWord) {
+ // If the word is encountered previously we just return its value present in the map (memoization).
+ if (memo.containsKey(currentWord)) {
+ return memo.get(currentWord);
+ }
+ // This stores the maximum length of word sequence possible with the 'currentWord' as the
+ int maxLength = 1;
+ StringBuilder sb = new StringBuilder(currentWord);
+
+ // creating all possible strings taking out one character at a time from the `currentWord`
+ for (int i = 0; i < currentWord.length(); i++) {
+ sb.deleteCharAt(i);
+ String newWord = sb.toString();
+ // If the new word formed is present in the list, we do a dfs search with this newWord.
+ if (words.contains(newWord)) {
+ int currentLength = 1 + dfs(words, memo, newWord);
+ maxLength = Math.max(maxLength, currentLength);
+ }
+ sb.insert(i, currentWord.charAt(i));
+ }
+ memo.put(currentWord, maxLength);
+
+ return maxLength;
+ }
+
+ public int longestStrChain(String[] words) {
+ Map memo = new HashMap<>();
+ Set wordsPresent = new HashSet<>();
+ Collections.addAll(wordsPresent, words);
+ int ans = 0;
+ for (String word : words) {
+ ans = Math.max(ans, dfs(wordsPresent, memo, word));
+ }
+ return ans;
+ }
+
+ public int longestStrChainBottomUp(String[] words) {
+ Map cache = new HashMap<>();
+
+
+ Arrays.sort(words, (a, b) -> Integer.compare(a.length(), b.length()));
+
+ int result = 0;
+
+ for (String word : words) {
+ int count = 0;
+
+ for (int i = 0; i < word.length(); i++) {
+ String temp = new StringBuilder(word).deleteCharAt(i).toString();
+ count = Math.max(count, cache.getOrDefault(temp, 0) + 1);
+
+ }
+
+ cache.put(word, count);
+ result = Math.max(result, count);
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/MaximumContiguousSubarraySum.java b/src/main/java/dynamicProgramming/lcs/MaximumContiguousSubarraySum.java
new file mode 100644
index 0000000..83170fe
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/MaximumContiguousSubarraySum.java
@@ -0,0 +1,28 @@
+package dynamicProgramming.lcs;
+
+/**
+ *
+ * http://tinyurl.com/y4mffrn7
+ */
+public class MaximumContiguousSubarraySum {
+
+ public static void main(String[] args) {
+ int[] arr2 = { -6, 2, -4, 1, 3, -1, 5, -1 };
+ MaximumContiguousSubarraySum mcs = new MaximumContiguousSubarraySum();
+ System.out.println(mcs.maxSubArray(arr2));
+
+ }
+
+ public int maxSubArray(int[] nums) {
+
+ int maxSoFar = nums[0];
+ int maxEndingHere = nums[0];
+
+ for (int i = 1; i < nums.length; i++) {
+ maxEndingHere = Math.max(maxEndingHere + nums[i], nums[i]);
+ maxSoFar = Math.max(maxSoFar, maxEndingHere);
+ }
+ return maxSoFar;
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/lcs/MaximumLengthRepeatedSubarray.java b/src/main/java/dynamicProgramming/lcs/MaximumLengthRepeatedSubarray.java
new file mode 100644
index 0000000..c961272
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/MaximumLengthRepeatedSubarray.java
@@ -0,0 +1,25 @@
+package dynamicProgramming.lcs;
+
+/**
+ * https://leetcode.com/problems/maximum-length-of-repeated-subarray/
+ *
+ * Idea is same as Longest common substring, in case of subsequence only we'll do if(nums1[i-1]!=nums2[j-1])
+ */
+public class MaximumLengthRepeatedSubarray {
+
+ public int findLength(int[] nums1, int[] nums2) {
+ int[][] dp = new int[nums1.length + 1][nums2.length + 1];
+
+ int result = 0;
+ for (int i = 1; i <= nums1.length; i++) {
+ for (int j = 1; j <= nums2.length; j++) {
+ if (nums1[i - 1] == nums2[j - 1]) {
+ dp[i][j] = 1 + dp[i - 1][j - 1];
+ result = Math.max(result, dp[i][j]);
+ }
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/MaximumSumIncreasingSubsequence.java b/src/main/java/dynamicProgramming/lcs/MaximumSumIncreasingSubsequence.java
new file mode 100644
index 0000000..7001da6
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/MaximumSumIncreasingSubsequence.java
@@ -0,0 +1,28 @@
+package dynamicProgramming.lcs;
+
+class MaximumSumIncreasingSubsequence {
+
+ static int maxSumIS(int arr[], int n) {
+ int i, j, max = 0;
+ int msis[] = new int[n];
+
+ for (i = 0; i < n; i++)
+ msis[i] = arr[i];
+
+ for (i = 1; i < n; i++) {
+ for (j = 0; j < i; j++) {
+ System.out.println(arr[i] + ">" + arr[j] + "&&" + msis[i] + "<" + (msis[j] + arr[i]));
+ if (arr[i] > arr[j] && msis[i] < msis[j] + arr[i])
+ msis[i] = msis[j] + arr[i];
+ max = Math.max(max,msis[i]);
+ }
+ }
+ return max;
+ }
+
+ public static void main(String args[]) {
+ int[] arr = new int[] { 1, 1001, 2, 3, 100, 4, 5 };
+ int n = arr.length;
+ System.out.println("Sum of maximum sum " + "increasing subsequence is " + maxSumIS(arr, n));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/lcs/MinimumAsciiDelete.java b/src/main/java/dynamicProgramming/lcs/MinimumAsciiDelete.java
new file mode 100644
index 0000000..098262d
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/MinimumAsciiDelete.java
@@ -0,0 +1,96 @@
+package dynamicProgramming.lcs;
+
+/**
+ * https://leetcode.com/problems/minimum-ascii-delete-sum-for-two-strings/
+ *
+ * In this question we are given two strings , and asked to get the sum of ASCII values, to make string same,
+ * RE-WORDING question : get the sum of all characters which do not form longest Common Subsequence.
+ *
+ * +------+-----+-------+------+------+
+ * | | "" | s (1) | e(2) | e(3) |
+ * +------+-----+-------+------+------+
+ * | "" | 0 | 101 | 198 | 314 |
+ * +------+-----+-------+------+------+
+ * | t(1) | 115 | 216 | 313 | 429 |
+ * +------+-----+-------+------+------+
+ * | e(2) | 216 | 115 | 212 | 328 |
+ * +------+-----+-------+------+------+
+ * | e(3) | 313 | | | |
+ * +------+-----+-------+------+------+
+ */
+public class MinimumAsciiDelete {
+
+
+ public int minimumDeleteSumTopDown(String s1, String s2) {
+ int[][] dp = new int[s1.length() + 1][s2.length() + 1];
+
+ // see first row and col, in order to equate chars to "", we need to delete chars
+ // so we add all chars
+ //if string_A or string_B is empty : then our ans is sum of all ASCII of non empty string
+ for (int i = 1; i <= s2.length(); i++) {
+ dp[0][i] = dp[0][i - 1] + s2.charAt(i - 1);
+ }
+ // refer above comment
+ for (int i = 1; i <= s1.length(); i++) {
+ dp[i][0] = dp[i - 1][0] + s1.charAt(i - 1);
+ }
+
+ for (int i = 1; i <= s1.length(); i++) {
+ for (int j = 1; j <= s2.length(); j++) {
+ //Of the two strings, if both of their last characters match
+ // then certainly the answer comes from skipping those characters.
+ //i.e. Answer("zca","bza") = Answer("zc","bz")
+ if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
+ dp[i][j] = dp[i - 1][j - 1];
+ } else {
+ //if the last characters are different then its one of the three situations:
+ //drop s1's last character (ASCII(s1's last) + dp[i-1][j])
+ //drop s2's last character (ASCII(s2's last) + dp[i][j-1])
+ // min of above 2
+ //One is to delete s1.charAt(i-1) ,based on the condition that s1[0:i-1] and s2[0:j] is already the same.
+ //The other is to delete s2.charAt(j-1),based on the condition that s1[0:i] and s2[0:j-1] is already the same.
+ dp[i][j] = Math.min(dp[i - 1][j] + s1.charAt(i - 1), dp[i][j - 1] + s2.charAt(j - 1));
+ }
+ }
+ }
+
+ return dp[s1.length()][s2.length()];
+ }
+
+
+ Integer[][] cache;
+
+ public int minimumDeleteSum(String s1, String s2) {
+ cache = new Integer[s1.length() + 1][s2.length() + 1];
+
+ return recursionHelper(s1, s2, 0, 0);
+
+ }
+
+ public int recursionHelper(String s1, String s2, int i, int j) {
+ if (i >= s1.length() && j >= s2.length()) return 0;
+ if (cache[i][j] != null) return cache[i][j];
+ if (i >= s1.length()) return getAscii(s2.substring(j));
+ if (j >= s2.length()) return getAscii(s1.substring(i));
+
+ int result = 0;
+
+ if (s1.charAt(i) == s2.charAt(j)) {
+ result += recursionHelper(s1, s2, i + 1, j + 1);
+ } else {
+ result += Math.min(recursionHelper(s1, s2, i + 1, j) + s1.charAt(i), recursionHelper(s1, s2, i, j + 1) + s2.charAt(j));
+ }
+
+ return cache[i][j] = result;
+
+ }
+
+ public int getAscii(String str) {
+ int res = 0;
+ for (char s : str.toCharArray()) {
+ res += s;
+ }
+ return res;
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/lcs/NumberOfDistinctSubSequence.java b/src/main/java/dynamicProgramming/lcs/NumberOfDistinctSubSequence.java
new file mode 100644
index 0000000..22f967c
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/NumberOfDistinctSubSequence.java
@@ -0,0 +1,56 @@
+package dynamicProgramming.lcs;
+
+public class NumberOfDistinctSubSequence {
+
+ Integer[][] cache;
+
+ public int numDistinct(String s, String t) {
+ cache = new Integer[s.length() + 1][t.length() + 1];
+ return recursionHelper(s, t, 0, 0);
+ }
+
+ public int recursionHelper(String s, String t, int idx1, int idx2) {
+
+ if (cache[idx1][idx2] != null) return cache[idx1][idx2];
+
+ if (idx1 == s.length() && idx2 < t.length()) return 0;
+ if (idx2 == t.length()) return 1;
+
+ int result = 0;
+ // if both chars are same we skip both, and also we explore by skipping the source index to find the target char elsewhere
+ if (s.charAt(idx1) == t.charAt(idx2)) {
+ result = recursionHelper(s, t, idx1 + 1, idx2 + 1) + recursionHelper(s, t, idx1 + 1, idx2);
+ }else{
+ // else we explore by skipping source index only because it's total ways
+ result += recursionHelper(s, t, idx1 + 1, idx2);
+ }
+
+
+ return cache[idx1][idx2] = result;
+ }
+
+ /**
+ * Copy the recurrence relation into tabulation that's all is the trick
+ */
+ public int numDistinctTopDown(String s, String t) {
+
+ int[][] dp = new int[s.length()+1][t.length()+1];
+
+ for(int i=0;i<=s.length();i++){
+ dp[i][0]=1;
+ }
+
+ for(int i=1;i<=s.length();i++){
+ for(int j=1;j<=t.length();j++){
+
+ if(s.charAt(i-1)==t.charAt(j-1)){
+ dp[i][j] = dp[i-1][j-1]+dp[i-1][j];
+ }else{
+ dp[i][j] = dp[i-1][j];
+ }
+ }
+ }
+
+ return dp[s.length()][t.length()];
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/NumberOfLIS.java b/src/main/java/dynamicProgramming/lcs/NumberOfLIS.java
new file mode 100644
index 0000000..7d56c21
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/NumberOfLIS.java
@@ -0,0 +1,76 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+
+/**
+ * tricky lis
+ * https://www.youtube.com/watch?v=_eHbuLHo6pM&ab_channel=LearnCodeRepeat
+ *
+ * While you're iterating over all the elements from '0' to 'i-1',
+ *
+ * First check whether the addition of the current element will form a LIS or not.
+ * (This statements denotes to check condition of nums[i] > nums[j])
+ *
+ * If a LIS is forming with the inclusion of element nums[i], then only a simple problem remains - Whether a subsequece of an equal length is already present or not.
+ *
+ * To resolve this problem, check whether you've already acheived a LIS of that length or not by simply comparing with the count[i].
+ *
+ * If yes, the count all the subsequences that have been formed at index 'j' and add them to the subsequences formed without subsequences ending at nums[j].
+ * (This statement denotes - dp[j] + 1 == dp[i])
+ *
+ * If not, then count all the subsequences formed with the subsequences ending at nums[j]
+ * (This statement denotes - dp[j] + 1 > dp[i])
+ *
+ * Arr => 1, 3, 5, 4, 7
+ * dp => 1, 2, 3, 3, 4
+ * cnt=> 1, 1, 1, 1, 2 when i at 7 and j at 4 dp[j] + 1 == dp[i] so count is 2
+ */
+public class NumberOfLIS {
+ public int findNumberOfLIS(int[] nums) {
+ int n = nums.length;
+ //dp[i] will store the length of Longest Increasing Subsequence, ending at nums[i].
+ int[] dp = new int[n];
+ //count[i] will store the total number of Longest Increasing Subsequences, ending at nums[i].
+ int[] count = new int[n];
+
+ Arrays.fill(dp,1);
+ Arrays.fill(count,1);
+ //lis : length of Longest Increasing Subsequence.
+ int lis = 0;
+ //res : total number of subsequences of length lis.
+ int res = 0;
+ for (int i = 1; i < n; i++) {
+ //Checking it's previous values.
+ for (int j = 0; j < i; j++) {
+ //If any previous value of nums[i] is less than it, then only it can be appended(as we know the
+ //subsequence would have ended at nums[j]).
+ if (nums[j] < nums[i]) {
+ //If dp[i] is equal to dp[j] + 1, meaning a different sequence has been found of same
+ //length, so increase count[i] by count[j].
+ if (dp[i] == dp[j] + 1) {
+ count[i] += count[j];
+ }
+ //Else, if dp[i] is less than dp[j] + 1, meaning length will increase as sequence will have a
+ //new element, so store dp[j] + 1 in dp[i] and count[j] in count[i].
+ else if (dp[i] < dp[j] + 1) {
+ dp[i] = dp[j] + 1;
+ count[i] = count[j];
+ }
+ }
+ }
+
+ //If lis is equal to dp[i], meaning a new sequence is found of same length, so add count[i] in res.
+ if (lis == dp[i]) {
+ res += count[i];
+ }
+ //Else if lis is less than dp[i], meaning a new sequence is formed of greater length, so store the
+ //new increased length in lis and count[i] in res.
+ else if (lis < dp[i]) {
+ lis = dp[i];
+ res = count[i];
+ }
+ }
+
+ return res;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/RussianDollEnvelope.java b/src/main/java/dynamicProgramming/lcs/RussianDollEnvelope.java
new file mode 100644
index 0000000..318277e
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/RussianDollEnvelope.java
@@ -0,0 +1,63 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+
+public class RussianDollEnvelope {
+
+ public int maxEnvelopes(int[][] envelopes) {
+
+ /**
+ * sort envelopes by width (envelopes[i][0]), then we only need to consider height
+ * //if two envelopes have same width, sort them by descending order
+ * //because [3, 4] cannot contains [3, 3], so we need to put [3, 4] before [3, 3] when sorting,
+ * //otherwise it will be counted as an increasing number if the order is [3, 3], [3, 4]
+ * //but we actually do not want to count them as valid russian doll envelopes
+ *
+ * prevent calculating the envelope with the same width? For example [3, 1] [3, 2] [3, 3] will get 3, but [3, 3], [3, 2], [3, 1] will get 1.
+ */
+ Arrays.sort(envelopes, (a, b) -> {
+ if (a[0] == b[0]) return Integer.compare(b[1], a[1]);
+ return Integer.compare(a[0], b[0]);
+ });
+ int result = 0;
+
+ /**
+ * //KEY POINTS: after sorting them by width with increasing order, we need to find Longest Increasing Subsequence
+ * //by traversing height of each envelope, then we get the final result
+ * //store tails of each increasing subsequence with different length
+ * /*eg: 3, 5, 1, 8, 2, 12
+ * * 1
+ * * 1, 2
+ * * 3, 5, 8
+ * * 3, 5, 8, 12
+ * * tails = {1, 2, 8, 12}
+ *
+ * //we do not care about what elements are in each subsequence, we only care about
+ * //tails of them, because every time we only compare with their tails to decide
+ * //which subsequence could we add new item and update the entire structure
+ */
+ int[] increasingHeight = new int[envelopes.length];
+
+ for (int[] envelope : envelopes) {
+
+ int left = 0;
+ int right = result;
+ while (left < right) {
+
+ int mid = left + (right - left) / 2;
+ if (increasingHeight[mid] < envelope[1]) {
+ left = mid + 1;
+ } else {
+ right = mid;
+ }
+ }
+
+ increasingHeight[left] = envelope[1];
+ if (left == result) {
+ result++;
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/ShortestCommonSupersequence.java b/src/main/java/dynamicProgramming/lcs/ShortestCommonSupersequence.java
new file mode 100644
index 0000000..d608268
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/ShortestCommonSupersequence.java
@@ -0,0 +1,65 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/shortest-common-supersequence/
+ *
+ *The idea is very simple. The result string should contain all characters of s1 and s2 discarding the common ones.
+ * -> S1+S2-LCS
+ * because characters appearing in LCS are coming twice in the result. So count them only once.
+ *
+ * O(MN) *O(String len) if we store string in DP
+ * else O(MN)
+ *
+ * Input: str1 = "abac", str2 = "cab"
+ * Output: "cabac"
+ * Explanation:
+ * str1 = "abac" is a subsequence of "cabac" because we can delete the first "c".
+ * str2 = "cab" is a subsequence of "cabac" because we can delete the last "ac".
+ * The answer provided is the shortest such string that satisfies these properties.
+ */
+public class ShortestCommonSupersequence {
+
+ public String shortestCommonSuperSequence(String str1, String str2) {
+
+ String lcs = longestCommonSubSeq(str1, str2);
+ int i = 0;
+ int j = 0;
+
+ StringBuilder sb = new StringBuilder();
+ for (char c : lcs.toCharArray()) {
+ while (i < str1.length() && str1.charAt(i) != c) sb.append(str1.charAt(i++));
+ while (j < str2.length() && str2.charAt(j) != c) sb.append(str2.charAt(j++));
+ sb.append(c);
+ i++;
+ j++;
+ }
+ sb.append(str1.substring(i));
+ sb.append(str2.substring(j));
+
+ return sb.toString();
+ }
+
+ public static void main(String[] args) {
+ new ShortestCommonSupersequence().shortestCommonSuperSequence("abac","cab");
+ }
+
+ public String longestCommonSubSeq(String str1, String str2) {
+ String[][] dp = new String[str1.length() + 1][str2.length() + 1];
+ for (String[] s : dp) {
+ Arrays.fill(s, "");
+ }
+ for (int i = 1; i < dp.length; i++) {
+ for (int j = 1; j < dp[0].length; j++) {
+ if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
+ dp[i][j] = dp[i - 1][j - 1] + str1.charAt(i - 1);
+ } else {
+ dp[i][j] = dp[i - 1][j].length() > dp[i][j - 1].length() ? dp[i - 1][j] : dp[i][j - 1];
+ }
+ }
+ }
+
+ return dp[str1.length()][str2.length()];
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/TwoStringInterleavingToFormThird.java b/src/main/java/dynamicProgramming/lcs/TwoStringInterleavingToFormThird.java
new file mode 100644
index 0000000..7a9abdf
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/TwoStringInterleavingToFormThird.java
@@ -0,0 +1,71 @@
+package dynamicProgramming.lcs;
+
+import java.util.Arrays;
+
+/**
+ * http://www.geeksforgeeks.org/check-whether-a-given-string-is-an-interleaving-of-two-other-given-strings-set-2/
+ */
+public class TwoStringInterleavingToFormThird {
+
+ public boolean isInterleave(String s1, String s2, String s3) {
+ int m = s1.length();
+ int n = s2.length();
+ if (m + n != s3.length()) return false;
+ boolean[][] dp = new boolean[m + 1][n + 1];
+ dp[0][0] = true;
+ for (int i = 1; i <= m; i++) {
+ if (dp[i - 1][0] && s1.charAt(i - 1) == s3.charAt(i - 1)) {
+ dp[i][0] = true;
+ }
+ }
+ for (int i = 1; i <= n; i++) {
+ if (dp[0][i - 1] && s2.charAt(i - 1) == s3.charAt(i - 1)) {
+ dp[0][i] = true;
+ }
+ }
+ for (int i = 1; i <= m; i++) {
+ for (int j = 1; j <= n; j++) {
+ if (s1.charAt(i - 1) == s3.charAt(i + j - 1) && dp[i - 1][j]) {
+ dp[i][j] = true;
+ }
+ if (s2.charAt(j - 1) == s3.charAt(i + j - 1) && dp[i][j - 1]) {
+ dp[i][j] = true;
+ }
+ }
+ }
+ return dp[m][n];
+ }
+
+ public static void main(String args[]) {
+ String str1 = "aab";
+ String str2 = "axy";
+ String str3 = "aaxaby";
+ TwoStringInterleavingToFormThird sti = new TwoStringInterleavingToFormThird();
+ System.out.println(sti.isInterleave(str1, str2, str3));
+ }
+
+ public boolean isInterleave(String s1, int i, String s2, int j, String s3, int k, Integer[][] memo) {
+ if (i == s1.length()) {
+ return s2.substring(j).equals(s3.substring(k));
+ }
+ if (j == s2.length()) {
+ return s1.substring(i).equals(s3.substring(k));
+ }
+ if (memo[i][j] !=null) {
+ return memo[i][j] == 1;
+ }
+ boolean ans = s3.charAt(k) == s1.charAt(i) && isInterleave(s1, i + 1, s2, j, s3, k + 1, memo)
+ || s3.charAt(k) == s2.charAt(j) && isInterleave(s1, i, s2, j + 1, s3, k + 1, memo);
+
+ memo[i][j] = ans ? 1 : 0;
+ return ans;
+ }
+ public boolean isInterleaveRecursive(String s1, String s2, String s3) {
+ if (s1.length() + s2.length() != s3.length()) {
+ return false;
+ }
+ Integer[][] memo= new Integer[s1.length()][s2.length()];
+
+ return isInterleave(s1, 0, s2, 0, s3, 0, memo);
+ }
+}
diff --git a/src/main/java/dynamicProgramming/lcs/WildCardMatching.java b/src/main/java/dynamicProgramming/lcs/WildCardMatching.java
new file mode 100644
index 0000000..b054e03
--- /dev/null
+++ b/src/main/java/dynamicProgramming/lcs/WildCardMatching.java
@@ -0,0 +1,123 @@
+package dynamicProgramming.lcs;
+
+/**
+ * General Idea: Credit: https://leetcode.com/problems/wildcard-matching/discuss/370736/Detailed-Intuition-From-Brute-force-to-Bottom-up-DP
+ * The idea is pretty straightforward : scan S and P while there is a match between the current character of S and the current character of P.
+ * If we reach the end of both strings while there is still a match, return True, otherwise return False.
+ * The scan is done by having a pointer in S and a pointer in P.
+
+ Example: S="code"
+ The character 'c' of S matches the first character of P if the first character of P is:
+
+ 'c'
+ '?'
+ '*'
+
+ Case 1:
+ When the first character of P is a lowercase letter different from 'c', return False.
+
+ Case 2:
+ If the first character of P is 'c' or '?', we move both pointers one step to the right.
+
+ Case 3:
+ If the first character of P is '*', we have 2 possibilities:
+
+ - '*' matches 0 character : in this case we move the pointer in P one step, ie will ignore the whole pattern
+ - '*' matches 1 or more characters : in this case we move the pointer in S one step, ie we consider pattern
+ And we continue like this for each two positions taken by the two pointers.
+
+ - If we reach the end of P but there is still characters from S, simply return .. False !
+ - If we reach the end of S and there is still characters from P, the only case when there is a match is that all the remaining characters in P are '*',
+ in this case these stars will be matched with the empty string.
+ **/
+public class WildCardMatching {
+
+ public boolean isMatch(String s, String p) {
+
+ return isMatchApproach1Helper(0, 0, s, p);
+ }
+
+ public boolean isMatchApproach1Helper(int tIdx, int pIdx, String text, String pattern) {
+
+ // reached the end of both S and P
+ if (tIdx == text.length() && pIdx == pattern.length()) {
+ return true;
+ }
+ // there are still characters in S => there is no match
+ else if (pIdx == pattern.length()) {
+ return false; // Can't have a non-empty s match an empty p.
+ }
+ // if we reached end of text and pattern is still left.
+ // Try to see if p at or after this stage is only * or ** or *** etc. Only way to match an empty text.
+ else if (tIdx == text.length()) {
+ return pattern.charAt(pIdx) == '*' && isMatchApproach1Helper(tIdx, pIdx + 1, text, pattern);
+ }
+ // Here cuz text & pattern match atleast a char
+ else if (text.charAt(tIdx) == pattern.charAt(pIdx) || pattern.charAt(pIdx) == '?') {
+ // Match here if strs from next index onward also are a match. Delegate job to recursive func for latter.
+ return isMatchApproach1Helper(tIdx + 1, pIdx + 1, text, pattern);
+ }
+
+ // star either matches 0 or >=1 character
+ else if (pattern.charAt(pIdx) == '*') {
+ // 1: When * matches an empty seq, it's work is done. Hence, the next stage to check match for is w/o *.
+ // Also, there could be *s in line. So, consuming this *, could exhibit new p with next fresh *.
+ // 2: '*' can match seq of chars. Hence, * kept. Further rec stages could use it to match more chars/empty.
+ return isMatchApproach1Helper(tIdx, pIdx + 1, text, pattern)
+ || isMatchApproach1Helper(tIdx + 1, pIdx, text, pattern);
+ }
+
+ return false;
+ }
+
+ /*******************
+ * Approach 3: Bottom Up Tabulation: https://www.youtube.com/watch?v=3ZDZ-N0EPV0
+ * Bottom-up the smallest is (0, 0)
+ *
+ * | dp[i-1][j-1] if str[i] == pattern[j] || pattern[j] == '?'
+ * |
+ * | if pattern[j-1] == '*'
+ * dp[i][j] = | dp[i][j-1] || dp[i-1][j]
+ * |
+ * | False
+ *
+ * Time Complexity : O(m * n)
+ * Space Complexity : O(m * n)
+ **********************************/
+ public boolean isMatchBottomUp(String s, String t) {
+ //First, we need to create a 2d dp table dp. The size of this table is (s.size() + 1) * (p.size() + 1).
+ // We introduce +1 here to better handle the edge cases where we have an empty string or an empty pattern.
+ boolean[][] dp= new boolean[s.length()+1][t.length()+1];
+
+ //When both the string and the pattern are empty.
+ //Always match. dp[0][0] = true
+ dp[0][0]= true;
+
+ for(int i=1;i<=t.length();i++){
+ if(t.charAt(i-1)=='*')
+ dp[0][i]= dp[0][i-1];
+ }
+
+ for(int i=1;i<=s.length();i++){
+ for(int j=1;j<=t.length();j++){
+
+ if(t.charAt(j-1)=='?' || s.charAt(i-1)==t.charAt(j-1)){
+ dp[i][j]=dp[i-1][j-1];
+
+ }else if(t.charAt(j-1)=='*'){
+ dp[i][j]= dp[i-1][j] || dp[i][j-1];
+ }else{
+ dp[i][j]=false;
+ }
+ }
+ }
+ return dp[s.length()][t.length()];
+ }
+
+ public static void main(String args[]) {
+ WildCardMatching wcm = new WildCardMatching();
+ System.out.println(wcm.isMatch("xbylmz", "x?y***z"));
+
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/matrix/MatrixMultiplicationCost.java b/src/main/java/dynamicProgramming/matrix/MatrixMultiplicationCost.java
new file mode 100644
index 0000000..bd53dd9
--- /dev/null
+++ b/src/main/java/dynamicProgramming/matrix/MatrixMultiplicationCost.java
@@ -0,0 +1,43 @@
+package dynamicProgramming.matrix;
+
+/**
+ * http://www.geeksforgeeks.org/dynamic-programming-set-8-matrix-chain-multiplication/
+ * https://www.youtube.com/watch?v=vgLJZMUfnsU&t=316s
+ */
+public class MatrixMultiplicationCost {
+
+
+ public static int matrixMultiplication(int[] arr, int N) {
+ Integer[][] dp = new Integer[N + 1][N + 1];
+ return recursionHelper(arr, 1, N - 1, dp);
+ }
+
+ public static int recursionHelper(int[] arr, int i, int j, Integer[][] dp) {
+ if (i == j) return 0;
+ if (dp[i][j] != null) return dp[i][j];
+ int min = Integer.MAX_VALUE;
+// Run a loop from 'i' to 'j' - 1 and calculate for all possible combination
+ for (int k = i; k < j; k++) {
+ min = Math.min(min, arr[i - 1] * arr[k] * arr[j] + recursionHelper(arr, i, k, dp) + recursionHelper(arr, k + 1, j, dp));
+ }
+
+ return dp[i][j] = min;
+ }
+
+ public static int matrixMultiplicationTabulation(int[] arr, int N) {
+ int[][] dp = new int[N][N];
+
+ for (int i = N - 1; i > 0; i--) {
+ for (int j = i + 1; j < N; j++) {
+
+ int min = Integer.MAX_VALUE;
+ for (int k = i; k < j; k++) {
+ min = Math.min(min, arr[i - 1] * arr[k] * arr[j] + dp[i][k] + dp[k + 1][j]);
+ }
+ dp[i][j] = min;
+ }
+ }
+
+ return dp[1][N - 1];
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/matrix/MaximumSquareDP.java b/src/main/java/dynamicProgramming/matrix/MaximumSquareDP.java
new file mode 100644
index 0000000..b5a4a1c
--- /dev/null
+++ b/src/main/java/dynamicProgramming/matrix/MaximumSquareDP.java
@@ -0,0 +1,51 @@
+package dynamicProgramming.matrix;
+
+class MaximumSquareDP {
+ public int maximalSquare(char[][] matrix) {
+ int[][] dp = new int[matrix.length][matrix[0].length];
+ int result = 0;
+ for (int i = 0; i < matrix[0].length; i++) {
+ dp[0][i] = matrix[0][i] == '1' ? 1 : 0;
+ result = Math.max(result, dp[0][i]);
+ }
+ for (int i = 0; i < matrix.length; i++) {
+ dp[i][0] = matrix[i][0] == '1' ? 1 : 0;
+ result = Math.max(result, dp[i][0]);
+ }
+
+ for (int i = 1; i < matrix.length; i++) {
+ for (int j = 1; j < matrix[0].length; j++) {
+ if (matrix[i][j] == '0') continue;
+
+ dp[i][j] = 1 + Math.min(dp[i - 1][j], Math.min(dp[i - 1][j - 1], dp[i][j - 1]));
+ result = Math.max(result, dp[i][j]);
+ }
+ }
+
+ return result * result;
+ }
+
+ public int maximalSquareRecursion(char[][] matrix) {
+ Integer[][] cache = new Integer[matrix.length][matrix[0].length];
+ int result = 0;
+ for (int i = 0; i < matrix.length; i++) {
+ for (int j = 0; j < matrix[0].length; j++) {
+ if (matrix[i][j] == '1') {
+ result = Math.max(result, dfs(matrix, cache, i, j));
+ }
+ }
+ }
+
+ return result * result;
+ }
+
+ public int dfs(char[][] matrix, Integer[][] cache, int i, int j) {
+ if (i >= matrix.length || j >= matrix[0].length || i < 0 || j < 0 || matrix[i][j] == '0') return 0;
+
+ if (cache[i][j] != null) return cache[i][j];
+
+ cache[i][j] = 1 + Math.min(dfs(matrix, cache, i + 1, j), Math.min(dfs(matrix, cache, i + 1, j + 1), dfs(matrix, cache, i, j + 1)));
+ return cache[i][j];
+ }
+}
+
diff --git a/src/main/java/dynamicProgramming/matrix/MinCostPath.java b/src/main/java/dynamicProgramming/matrix/MinCostPath.java
new file mode 100644
index 0000000..f1d04e1
--- /dev/null
+++ b/src/main/java/dynamicProgramming/matrix/MinCostPath.java
@@ -0,0 +1,52 @@
+package dynamicProgramming.matrix;
+
+/**
+ * http://www.geeksforgeeks.org/dynamic-programming-set-6-min-cost-path/
+ */
+public class MinCostPath {
+
+ public int minPathSum1(int[][] grid) {
+
+ for(int i=1;i 0) {
+ min = Math.min(min, matrix[i - 1][j - 1]);
+ }
+
+ if (j < n - 1) {
+ min = Math.min(min, matrix[i - 1][j + 1]);
+ }
+
+ matrix[i][j] += min;
+ }
+ }
+
+ return Arrays.stream(matrix[m - 1]).min().getAsInt();
+ }
+
+ public static void main(String[] args) {
+ minFallingPathSum(new int[][]{{2, 1, 3},
+ {6, 5, 4},
+ {7, 8, 9}});
+ }
+}
diff --git a/src/main/java/dynamicProgramming/oiknapsack/EqualSubsetSumPartition.java b/src/main/java/dynamicProgramming/oiknapsack/EqualSubsetSumPartition.java
new file mode 100644
index 0000000..e1676c6
--- /dev/null
+++ b/src/main/java/dynamicProgramming/oiknapsack/EqualSubsetSumPartition.java
@@ -0,0 +1,108 @@
+package dynamicProgramming.oiknapsack;
+
+import java.util.Arrays;
+
+/**
+ * https://www.educative.io/collection/page/5668639101419520/5633779737559040/5752754626625536
+ *
+ * Given a non-empty array containing only positive integers,
+ * find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.
+ *
+ * Input: [1, 5, 11, 5]
+ *
+ * Output: true
+ *
+ * Explanation: The array can be partitioned as [1, 5, 5] and [11].
+ */
+class EqualSubsetSumPartition {
+
+// 0 1 2 3 4 5
+// +---+---+---+---+---+---+
+// {1} | T | T | F | F | F | F |
+// +---+---+---+---+---+---+
+// {1,2} | T | T | T | T | F | F |
+// +---+---+---+---+---+---+
+// {1,2,3} | T | T | T | T | T | T |
+// +---+---+---+---+---+---+
+//{1,2,3,4} | T | T | T | T | T | T |
+// +---+---+---+---+---+---+
+
+ public boolean canPartition(int[] nums) {
+ int totalSum = 0;
+ // find sum of all array elements
+ for (int num : nums) {
+ totalSum += num;
+ }
+ // if totalSum is odd, it cannot be partitioned into equal sum subset
+ if (totalSum % 2 != 0) return false;
+ int subSetSum = totalSum / 2;
+ int n = nums.length;
+ boolean dp[][] = new boolean[n + 1][subSetSum + 1];
+ dp[0][0] = true;
+ for (int i = 1; i <= n; i++) {
+ int curr = nums[i - 1];
+ for (int j = 0; j <= subSetSum; j++) {
+ if (j < curr)
+ dp[i][j] = dp[i - 1][j];
+ else
+ dp[i][j] = dp[i - 1][j] || (dp[i - 1][j - curr]);
+ }
+ }
+ return dp[n][subSetSum];
+ }
+
+ Boolean[][] cache;
+
+ public boolean canPartitionBottomUp(int[] nums) {
+
+ int sum = 0;
+ for (int num : nums) {
+ sum += num;
+ }
+ if (sum % 2 == 1) return false;
+ int target = sum / 2;
+ cache = new Boolean[nums.length + 1][target + 1];
+ return sumPossible(nums, 0, target);
+ }
+
+ public boolean sumPossible(int[] nums, int i, int target) {
+ if (target < 0) return false;
+ if (target == 0) return true;
+ if (i >= nums.length) return false;
+ if (cache[i][target] != null) return cache[i][target];
+
+ return cache[i][target] = sumPossible(nums, i + 1, target - nums[i]) || sumPossible(nums, i + 1, target);
+ }
+
+ public boolean canPartitionSpace(int[] nums) {
+ int sum = 0;
+ for (int i : nums) {
+ sum += i;
+ }
+
+ if (sum % 2 == 1) return false;
+ int target = sum / 2;
+ boolean[] dp = new boolean[target + 1];
+ dp[0] = true;
+
+ for (int num : nums) {
+ for (int i = target; i > 0; i--) {
+
+ // Go from behind to preserve data!
+ // We only need data from the previous number
+ // being looked at, that means the previous row.
+ // If we go from behind, that information is preserved.
+
+ if (i - num >= 0) dp[i] = dp[i] || dp[i - num];
+ }
+ }
+
+ return dp[target];
+ }
+
+ public static void main(String[] args) {
+ EqualSubsetSumPartition ps = new EqualSubsetSumPartition();
+ int[] num = {2, 3, 4, 5};
+ System.out.println(ps.canPartition(num));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/oiknapsack/MinPartition.java b/src/main/java/dynamicProgramming/oiknapsack/MinPartition.java
new file mode 100644
index 0000000..189cc40
--- /dev/null
+++ b/src/main/java/dynamicProgramming/oiknapsack/MinPartition.java
@@ -0,0 +1,46 @@
+package dynamicProgramming.oiknapsack;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class MinPartition
+{
+
+ public static int minPartition(int[] S, int n, int S1, int S2,
+ Map lookup)
+ {
+ if (n < 0) {
+ return Math.abs(S1 - S2);
+ }
+
+ // construct a unique map key from dynamic elements of the input
+ // Note that can uniquely identify the subproblem with n & S1 only,
+ // as S2 is nothing but S - S1 where S is sum of all elements
+ String key = n + "|" + S1;
+
+ // if sub-problem is seen for the first time, solve it and
+ // store its result in a map
+ if (!lookup.containsKey(key))
+ {
+ // Case 1. include current item in the subset S1 and recurse
+ // for remaining items (n - 1)
+ int inc = minPartition(S, n - 1, S1 + S[n], S2, lookup);
+
+ // Case 2. exclude current item from subset S1 and recurse for
+ // remaining items (n - 1)
+ int exc = minPartition(S, n - 1, S1, S2 + S[n], lookup);
+
+ lookup.put(key, Integer.min(inc, exc));
+ }
+
+ return lookup.get(key);
+ }
+
+ public static void main(String[] args)
+ {
+ int[] S = { 10, 20, 15, 5, 25 };
+ Map lookup = new HashMap<>();
+ System.out.println("The minimum difference is "
+ + minPartition(S, S.length - 1, 0, 0, lookup));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/oiknapsack/MinimumSubsetSum.java b/src/main/java/dynamicProgramming/oiknapsack/MinimumSubsetSum.java
new file mode 100644
index 0000000..afbc06d
--- /dev/null
+++ b/src/main/java/dynamicProgramming/oiknapsack/MinimumSubsetSum.java
@@ -0,0 +1,17 @@
+package dynamicProgramming.oiknapsack;
+
+/**
+ * Given a set of positive numbers, partition the set into two subsets with minimum difference between their subset sums.
+ * Input: {1, 2, 3, 9}
+ * Output: 3
+ * Explanation: We can partition the given set into two subsets where minimum absolute difference
+ * between the sum of numbers is '3'. Following are the two subsets: {1, 2, 3} & {9}.
+ *
+ * Input: {1, 3, 100, 4}
+ * Output: 92
+ * Explanation: We can partition the given set into two subsets where minimum absolute difference
+ * between the sum of numbers is '92'. Here are the two subsets: {1, 3, 4} & {100}.
+ */
+public class MinimumSubsetSum {
+
+}
diff --git a/src/main/java/dynamicProgramming/oiknapsack/NumberOfUniqueWaysToMakeChange.java b/src/main/java/dynamicProgramming/oiknapsack/NumberOfUniqueWaysToMakeChange.java
new file mode 100644
index 0000000..3c4db76
--- /dev/null
+++ b/src/main/java/dynamicProgramming/oiknapsack/NumberOfUniqueWaysToMakeChange.java
@@ -0,0 +1,34 @@
+package dynamicProgramming.oiknapsack;
+
+import java.util.Arrays;
+
+/*
+ * Java-solution-with-thinking-process-O(nm)-Time-and-O(m)-Space Note: This code
+ * shows the use of O(mn) space. This problem can be solved using only O(m)
+ * space. https://www.youtube.com/watch?v=DJ4a7cmjZY0
+ */
+public class NumberOfUniqueWaysToMakeChange {
+
+ public int numberOfSolutions(int total, int coins[]) {
+ int[][] temp = new int[coins.length + 1][total + 1];
+ for (int i = 0; i <= coins.length; i++) {
+ temp[i][0] = 1;
+ }
+ for (int i = 1; i <= coins.length; i++) {
+ for (int j = 1; j <= total; j++) {
+ if (coins[i - 1] > j) {
+ temp[i][j] = temp[i - 1][j];
+ } else {
+ temp[i][j] = temp[i][j - coins[i - 1]] + temp[i - 1][j];
+ }
+ }
+ System.out.println(Arrays.toString(temp[i]));
+ }
+ return temp[coins.length][total];
+ }
+
+ public static void main(String[] args) {
+ int[] coins = { 1, 2, 5 };
+ System.out.println(new NumberOfUniqueWaysToMakeChange().numberOfSolutions(5, coins));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/oiknapsack/O1KnapsackSpaceOptimized.java b/src/main/java/dynamicProgramming/oiknapsack/O1KnapsackSpaceOptimized.java
new file mode 100644
index 0000000..13c4396
--- /dev/null
+++ b/src/main/java/dynamicProgramming/oiknapsack/O1KnapsackSpaceOptimized.java
@@ -0,0 +1,105 @@
+package dynamicProgramming.oiknapsack;
+
+class O1KnapsackSpaceOptimized {
+
+ public static void main(String[] args) {
+ int wt[] = { 2, 3, 4, 5 };
+ int val[] = { 1, 2, 4, 6 };
+ int W = 7;
+ int n = 4;
+ System.out.println(findProfit(val, wt, W));
+ }
+
+ public static int findProfit(int[] val, int[] wt, int W) {
+ int[][] profits = new int[val.length + 1][W + 1];
+ for (int i = 1; i <= val.length; i++) {
+ int currWeight = wt[i - 1];
+ for (int j = 1; j <= W; j++) {
+// So, for each item at index ‘i’ (0 <= i < items.length) and capacity ‘c’ (0 <= c <= capacity), we have two options:
+// Include the item at index ‘i’ if its weight is not more than the capacity.
+// In this case, we include its profit plus whatever profit we get from the remaining capacity
+// and from remaining items => profit[i] + dp[i-1][c-weight[i]]
+ if (j - currWeight >= 0) {
+ profits[i][j] = Math.max(profits[i - 1][j], profits[i - 1][j - currWeight] + val[i - 1]);
+ }
+// Exclude the item at index ‘i’.
+// In this case, we will take whatever profit we get from the sub-array excluding this item => dp[i-1][c]
+ else {
+ profits[i][j] = profits[i - 1][j];
+ }
+ }
+ }
+ return profits[val.length][W];
+ }
+
+// 1) When we access dp[j], it has not been overridden yet for the current iteration, so it should be fine.
+// 2) dp[j-weight[i]] might be overridden if “weight[i] > 0”. Therefore we can’t use this value for the current iteration.
+
+// To solve the second case, we can change our inner loop to process in the reverse direction: c:capacity-->0.
+// This will ensure that whenever we change a value in dp[], we will not need it again in the current iteration.
+
+ public int findProfitSpaceOptimised(int[] val, int[] wt, int W){
+ int[] profits = new int[W + 1];
+ // if we have only one weight we take if it's not more than the capacity
+ for (int c=0; c<=W;c++){
+ if(wt[0]= 0; j--){
+ int profit1 = 0, profit2=0;
+ if(wt[i-1]<=j){
+ profit1= val[i-1]+profits[j-wt[i-1]];
+ }
+ profit2=profits[j];
+ profits[j]= Math.max(profit1,profit2);
+ }
+ }
+ return profits[W];
+ }
+
+// Input: m = 10, A = [2, 3, 5, 7], V = [1, 5, 2, 4]
+// Output: 9
+// Explanation: Put A[1] and A[3] into backpack, getting the maximum value V[1] + V[3] = 9
+
+ public int backPackII(int m, int[] A, int[] V) {
+
+ int[][] dp= new int[A.length+1][m+1];
+
+ for(int i=1;i<=A.length;i++) {
+ for (int j = 1; j <= m; j++) {
+ if (A[i - 1] > m) {
+ dp[i][j] = dp[i - 1][j];
+ } else {
+ int prevVal = j >= m ? dp[i - 1][j - m] : 0;
+ dp[i][j] = Math.max(dp[i - 1][j],
+ V[i - 1] + prevVal);
+ }
+ }
+ }
+ return dp[A.length][m];
+
+ }
+
+ private static int unboundedKnapsack(int W, int n,
+ int[] val, int[] wt)
+ {
+
+ // dp[i] is going to store maximum value
+ // with knapsack capacity i.
+ int dp[] = new int[W + 1];
+
+ // Fill dp[] using above recursive formula
+ for(int i = 0; i <= W; i++){
+ for(int j = 0; j < n; j++){
+ if(wt[j] <= i){
+ dp[i] = Math.max(dp[i], dp[i - wt[j]] +
+ val[j]);
+ }
+ }
+ }
+ return dp[W];
+ }
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/oiknapsack/SubsetSumProblem.java b/src/main/java/dynamicProgramming/oiknapsack/SubsetSumProblem.java
new file mode 100644
index 0000000..22b620a
--- /dev/null
+++ b/src/main/java/dynamicProgramming/oiknapsack/SubsetSumProblem.java
@@ -0,0 +1,99 @@
+package dynamicProgramming.oiknapsack;
+
+import java.util.ArrayList;
+
+//Given a set of positive numbers, determine if a subset exists whose sum is equal to a given number ‘S’.
+
+/**
+ * Input: {1, 2, 3, 7}, S=6
+ * Output: True
+ * The given set has a subset whose sum is '6': {1, 2, 3}
+ *
+ * Input: {1, 2, 7, 1, 5}, S=10
+ * Output: True
+ * The given set has a subset whose sum is '10': {1, 2, 7}
+ */
+
+// 0 1 2 3 4 5 6
+// +---+---+---+---+---+---+---+
+// {1} | T | T | F | F | F | F | F |
+// +---+---+---+---+---+---+---+
+// {1,2} | T | T | T | T | F | F | F |
+// +---+---+---+---+---+---+---+
+// {1,2,3} | T | T | T | T | T | T | T |
+// +---+---+---+---+---+---+---+
+// {1,2,3,7} | T | T | T | T | T | T | T |
+// +---+---+---+---+---+---+---+
+public class SubsetSumProblem {
+
+ static boolean[][] dp;
+
+ static void printAllSubsets(int arr[], int n, int sum) {
+ if (n == 0 || sum < 0)
+ return;
+
+ dp = new boolean[n][sum + 1];
+ for (int i = 0; i < n; ++i) {
+ dp[i][0] = true;
+ }
+
+ if (arr[0] <= sum)
+ dp[0][arr[0]] = true;
+
+ for (int i = 1; i < n; ++i) {
+ for (int j = 0; j <= sum; j++) {
+ if (arr[i] <= j) {
+ dp[i][j] = (dp[i - 1][j] || dp[i - 1][j - arr[i]]);
+ } else {
+ dp[i][j] = dp[i - 1][j];
+ }
+ }
+ }
+ if (!dp[n - 1][sum]) {
+ System.out.println("There are no subsets with" + " sum " + sum);
+ return;
+ }
+
+ ArrayList p = new ArrayList<>();
+ }
+
+ public boolean canPartition(int[] nums) {
+ if(nums==null || nums.length==0) return false;
+
+ int sum=0;
+ for(int i: nums){
+ sum+=i;
+ }
+ // odd numbers cannot be partitioned
+ if ((sum & 1) == 1) {
+ return false;
+ }
+ sum/=2; // checking for half of the the sum
+ boolean[][] dp= new boolean[nums.length+1][sum+1];
+
+ for(int i=0; i<=nums.length;i++){
+ dp[i][0]= true; // first index of all rows are true because 0 is present in 0,0
+ }
+ for(int i=1;i<=nums.length; i++){
+ for(int j=1; j<=sum;j++){
+
+ if(nums[i-1]>j){
+ dp[i][j]= dp[i-1][j];
+ }else{
+ dp[i][j]= (dp[i - 1][j] || dp[i-1][j-nums[i-1]]);
+ }
+ }
+ }
+
+
+
+ return dp[nums.length][sum];
+ }
+
+ public static void main(String args[]) {
+ int arr[] = { 2, 3, 5, 8, 10 };
+ int n = arr.length;
+ int sum = 10;
+ printAllSubsets(arr, n, sum);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/palindrome/CountSubStrings.java b/src/main/java/dynamicProgramming/palindrome/CountSubStrings.java
new file mode 100644
index 0000000..17f918f
--- /dev/null
+++ b/src/main/java/dynamicProgramming/palindrome/CountSubStrings.java
@@ -0,0 +1,57 @@
+package dynamicProgramming.palindrome;
+
+public class CountSubStrings {
+ public int countSubstrings(String s) {
+ int count = 0;
+ for (int i = 0; i < s.length(); i++)
+ count += countSubstrings(s, i, i) + countSubstrings(s, i, i + 1);
+ return count;
+ }
+
+ private int countSubstrings(String s, int start, int end) {
+ int count = 0;
+ while (start >= 0 && end < s.length() && s.charAt(start--) == s.charAt(end++))
+ count++;
+ return count;
+ }
+
+ public static int countSubstring(String s) {
+ int n = s.length();
+ if (n < 2)
+ return n;
+ int count = n;
+ boolean[][] dp = new boolean[n][n];
+
+ // size 1 substrings are palindromes
+ for (int i = 0; i < n; i++)
+ dp[i][i] = true;
+
+ // for size 2 substrings, check first and last char
+ for (int i = 0; i + 1 < n; i++)
+ if (s.charAt(i) == s.charAt(i + 1)) {
+ dp[i][i + 1] = true;
+ count++;
+ }
+
+ // for size = 3+
+ for (int len = 2; len < n; len++) // controls the size of the substring
+ for (int i = 0; i + len < n; i++) { // controls the start index
+ int j = i + len; // end index
+ System.out.print(i + " - " + j + " ");
+ // if s.charAt(i) == s.charAt(j) means the substring's first and last are equal letters
+ // we don't have to check the contents, we just have to check if lower diagonal is true
+ // lower diagonal is the result of the content in between s.charAt(i) == s.charAt(j)
+
+ if ((s.charAt(i) == s.charAt(j)) && dp[i + 1][j - 1]) {
+ dp[i][j] = true;
+ count++;
+ }
+ System.out.println();
+ }
+ return count;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(countSubstring("aaaa"));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/palindrome/LongestPalindromicSubsequence.java b/src/main/java/dynamicProgramming/palindrome/LongestPalindromicSubsequence.java
new file mode 100644
index 0000000..cadc967
--- /dev/null
+++ b/src/main/java/dynamicProgramming/palindrome/LongestPalindromicSubsequence.java
@@ -0,0 +1,86 @@
+package dynamicProgramming.palindrome;
+
+import java.util.Arrays;
+
+/**
+ * Date 08/01/2014
+ *
+ * @author Tushar Roy
+ *
+ * Time complexity - O(n2) Space complexity - O(n2)
+ *
+ * Youtube link - https://youtu.be/_nCsPn7_OgI
+ *
+ * References
+ * http://www.geeksforgeeks.org/dynamic-programming-set-12-longest-palindromic-subsequence/
+ */
+public class LongestPalindromicSubsequence {
+
+ public int calculate1(char[] str) {
+ int[][] T = new int[str.length][str.length];
+ for (int i = 0; i < str.length; i++) {
+ T[i][i] = 1;
+ }
+ for (int l = 2; l < str.length; l++) {
+ for (int i = 0; i+l < str.length ; i++) {
+ int j = i + l;
+ if (l == 2 && str[i] == str[j]) {
+ T[i][j] = 2;
+ } else if (str[i] == str[j]) {
+ T[i][j] = T[i + 1][j - 1] + 2;
+ } else {
+ T[i][j] = Math.max(T[i + 1][j], T[i][j - 1]);
+ }
+ }
+ }
+ return T[0][str.length - 1];
+ }
+
+ public int longestPalindromeSubseq(String s) {
+ char[] chars = s.toCharArray();
+ int n = s.length();
+ int[][] dp = new int[n][n];
+ for (int i = n - 1; i >= 0; i--) {
+ dp[i][i] = 1;
+ for (int j = i + 1; j < n; ++j) {
+ if (chars[i] == chars[j]) {
+ dp[i][j] = dp[i + 1][j - 1] + 2;
+ } else {
+ dp[i][j] = Math.max(dp[i + 1][j], dp[i][j - 1]);
+ }
+ }
+ }
+ for (int[] ints : dp) {
+ System.out.println(Arrays.toString(ints));
+ }
+ return dp[0][n - 1];
+
+ }
+
+ public int longestPalindromeSubseqRecusive(String s) {
+ return helper(s, 0, s.length() - 1, new Integer[s.length()][s.length()]);
+ }
+
+ private int helper(String s, int i, int j, Integer[][] memo) {
+ if (memo[i][j] != null) {
+ return memo[i][j];
+ }
+ if (i > j) return 0;
+ if (i == j) return 1;
+
+ if (s.charAt(i) == s.charAt(j)) {
+ memo[i][j] = helper(s, i + 1, j - 1, memo) + 2;
+ } else {
+ memo[i][j] = Math.max(helper(s, i + 1, j, memo), helper(s, i, j - 1, memo));
+ }
+ return memo[i][j];
+ }
+
+ public static void main(String args[]) {
+ LongestPalindromicSubsequence lps = new LongestPalindromicSubsequence();
+ String str = "agbdba";
+ int r2 = lps.longestPalindromeSubseq(str);
+ System.out.print(r2);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/palindrome/LongestPalindromicSubstring.java b/src/main/java/dynamicProgramming/palindrome/LongestPalindromicSubstring.java
new file mode 100644
index 0000000..b2a3e07
--- /dev/null
+++ b/src/main/java/dynamicProgramming/palindrome/LongestPalindromicSubstring.java
@@ -0,0 +1,45 @@
+package dynamicProgramming.palindrome;
+
+/**
+ * https://leetcode.com/problems/longest-palindromic-substring/
+ */
+public class LongestPalindromicSubstring {
+
+ public static String longestPalindrome(String s) {
+ int len = s.length();
+ if (len < 2)
+ return s;
+ int[] maxStart = new int[1], maxEnd = new int[1];
+ // odd length ababc => here we start j and k at same position say index 2 and go left and right
+ // even length cbbd=> here let's say we're at index 1, we need to take 1 and 2 index to check for palindrome
+ // the above cases are the reason for sending i and i+1
+ for (int i = 0; i < s.length() - 1; i++) {
+ extend(s, i, i, maxStart, maxEnd);
+ extend(s, i, i + 1, maxStart, maxEnd);
+ }
+
+ return s.substring(maxStart[0], maxEnd[0] + 1);
+ }
+
+ private static void extend(String s, int i, int j, int[] maxStart, int[] maxEnd) {
+ // loop until meet invalid match
+ while (i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j)) {
+ i--;
+ j++;
+ }
+
+ i++;
+ j--; // back to the last valid match
+
+ if (j - i + 1 > maxEnd[0] - maxStart[0] + 1) {
+ maxStart[0] = i;
+ maxEnd[0] = j;
+ }
+ }
+
+
+ public static void main(String args[]) {
+
+ System.out.println(longestPalindrome("bananas"));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/dynamicProgramming/palindrome/PalindromePartitioning.java b/src/main/java/dynamicProgramming/palindrome/PalindromePartitioning.java
new file mode 100644
index 0000000..3280e12
--- /dev/null
+++ b/src/main/java/dynamicProgramming/palindrome/PalindromePartitioning.java
@@ -0,0 +1,65 @@
+package dynamicProgramming.palindrome;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * https://leetcode.com/problems/palindrome-partitioning/
+ * The aim to partition the string into all possible palindrome combinations.
+ * To achieve this, we must generate all possible substrings of a string by partitioning at every index
+ * until we reach the end of the string.
+ * Example, abba can be partitioned as ["a","ab","abb","abba"].
+ * Each generated substring is considered as a potential candidate if it's a Palindrome
+ */
+class PalindromePartitioning {
+
+ public List> partition(String s) {
+ if (s == null || s.length() == 0) {
+ return Collections.emptyList();
+ }
+
+ List> result = new ArrayList<>();
+ backtrackingUtil(s, result, new ArrayList<>(), 0);
+
+ return result;
+ }
+
+ public void backtrackingUtil(String s, List> result, List tempList, int start) {
+ if (start >= s.length()) {
+ result.add(new ArrayList<>(tempList));
+ return;
+ }
+
+ for (int i = start; i < s.length(); i++) {
+ String temp = s.substring(start, i + 1);
+ if (isPalindrome(temp)) {
+ tempList.add(temp);
+ backtrackingUtil(s, result, tempList, i + 1);
+ tempList.remove(tempList.size() - 1);
+ }
+ }
+ }
+
+ public boolean isPalindrome(String s) {
+ int start = 0;
+ int end = s.length() - 1;
+ while (start <= end) {
+ if (s.charAt(start) != s.charAt(end)) {
+ return false;
+ }
+ start++;
+ end--;
+ }
+ return true;
+ }
+
+ public static void main(String[] args) {
+ PalindromePartitioning partitioning = new PalindromePartitioning();
+ partitioning.partition("aab");
+ }
+}
+
+
+
+
diff --git a/src/main/java/dynamicProgramming/palindrome/PalindromePartitioningII.java b/src/main/java/dynamicProgramming/palindrome/PalindromePartitioningII.java
new file mode 100644
index 0000000..d227e5e
--- /dev/null
+++ b/src/main/java/dynamicProgramming/palindrome/PalindromePartitioningII.java
@@ -0,0 +1,111 @@
+package dynamicProgramming.palindrome;
+
+/**
+ * revise
+ * https://leetcode.com/problems/palindrome-partitioning-ii
+ */
+public class PalindromePartitioningII {
+
+ public static int minCutPalindromicSubstringVariant(String s) {
+ int[] cutsDp = new int[s.length()];
+ for (int i = 1; i < s.length(); i++) {
+ cutsDp[i] = i;
+ }
+
+ for (int mid = 0; mid < s.length(); mid++) {
+ findMin(mid, mid, cutsDp, s);
+ findMin(mid, mid + 1, cutsDp, s);
+ }
+
+ return cutsDp[s.length() - 1];
+ }
+
+ public static void findMin(int start, int end, int[] cutsDp, String s) {
+ for (int i = start, j = end; i >= 0 && j < s.length() && s.charAt(i) == s.charAt(j); i--, j++) {
+ int newCut = i == 0 ? 0 : cutsDp[i - 1] + 1;
+ cutsDp[j] = Math.min(cutsDp[j], newCut);
+ }
+ }
+
+ public static void main(String[] args) {
+ minCutPalindromicSubstringVariant("nooradars");
+ }
+
+ public int minCut(String s) {
+ int n, min;
+ n = s.length();
+
+ //cut[i] represents minimum number of cuts from String 0 to i
+ int[] cut = new int[n];
+
+ //p[i][j] represents String i to j is a palindrome or not
+ boolean[][] p = new boolean[n][n];
+
+ for (int i = 0; i < n; i++) {
+ min = i; // Max number of cuts is i for string length i+1
+ for (int j = 0; j <= i; j++) {
+ // Why i - j < 3 ?
+ // 1. String of length 1 is always palindrome so no need to check in boolean table
+ // 2. String of length 2 is palindrome if Ci == Cj which is already checked in first part so no need to check again
+ // 3. String of length 3 is palindrome if Ci == Cj which is already checked in first part and Ci+1 and Cj-1 is same character which is always a palindrome
+
+ // If String length >=4
+ // then check if Ci == Cj and if they are equal check if String[j+1 .. i-1] is a palindrome from the boolean table
+ /**
+ * a b a | c c
+ * j i
+ * j-1 | [j, i] is palindrome
+ * cut(j-1) + 1
+ */
+ if (s.charAt(j) == s.charAt(i) && (i - j < 3 || p[j + 1][i - 1])) {
+ // Its a palindrome as Ci == Cj and String[j+1...i-1] is a palindrome
+ p[j][i] = true;
+ // j == 0 because String from j to i is a palindrome and it starts from first character so means no cuts needed
+ // Else I need a cut at jth location and it will be cuts encountered till j-1 + 1
+ min = j == 0 ? 0 : Math.min(min, cut[j - 1] + 1);
+ }
+ }
+ cut[i] = min;
+ }
+ return cut[n - 1];
+ }
+
+
+ Integer[][] cache;
+
+ public int minCutRecursive(String s) {
+ cache = new Integer[s.length() + 1][s.length() + 1];
+
+ return recursionHelper(s, 0, s.length() - 1);
+ }
+
+ public int recursionHelper(String s, int start, int end) {
+ if (start == end || isPalin(s, start, end)) {
+ return 0;
+ }
+ if (cache[start][end] != null) return cache[start][end];
+
+ int minCuts = end - start;
+ for (int i = start; i <= end; i++) {
+ if (isPalin(s, start, i)) {
+ minCuts = Math.min(minCuts, 1 + recursionHelper(s, i + 1, end));
+ }
+ }
+
+ return cache[start][end] = minCuts;
+ }
+
+ public boolean isPalin(String s, int start, int end) {
+ if (start > end) return false;
+
+ while (start < end) {
+ if (s.charAt(start) != s.charAt(end)) return false;
+
+ start++;
+ end--;
+ }
+
+ return true;
+
+ }
+}
diff --git a/src/main/java/dynamicProgramming/stocks/BuyAndSellStockAnytime.java b/src/main/java/dynamicProgramming/stocks/BuyAndSellStockAnytime.java
new file mode 100644
index 0000000..c2388f8
--- /dev/null
+++ b/src/main/java/dynamicProgramming/stocks/BuyAndSellStockAnytime.java
@@ -0,0 +1,29 @@
+package dynamicProgramming.stocks;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/
+ */
+public class BuyAndSellStockAnytime {
+
+ public int maxProfit(int[] prices) {
+ int total = 0;
+ for (int i = 0; i < prices.length - 1; i++) {
+ if (prices[i + 1] > prices[i]) {
+ total += prices[i + 1] - prices[i];
+ System.out.println(prices[i + 1] +" - "+ prices[i] +" = "+(prices[i + 1] - prices[i]));
+ }
+ }
+ return total;
+ }
+
+
+
+ public static void main(String[] args) {
+ BuyAndSellStockAnytime stock = new BuyAndSellStockAnytime();
+ int[] arr = {200, 180, 260, 310, 40, 535, 695};
+ System.out.println(stock.maxProfit(arr));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/stocks/BuyAndSellStockAtMostTwice.java b/src/main/java/dynamicProgramming/stocks/BuyAndSellStockAtMostTwice.java
new file mode 100644
index 0000000..5d19e78
--- /dev/null
+++ b/src/main/java/dynamicProgramming/stocks/BuyAndSellStockAtMostTwice.java
@@ -0,0 +1,74 @@
+package dynamicProgramming.stocks;
+
+/**
+ * https://leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/
+ */
+class BuyAndSellStockAtMostTwice {
+
+ public static void main(String args[]) {
+ System.out.println("Maximum Profit = " + maxProfit(new int[]{2, 30, 15, 10, 8, 25, 80}));
+ }
+
+ /**
+ * the idea is when we find a profit which is from
+ * i to n, we can break it in to i to k, k+1 to n
+ * in this manner at each point we can calculate profit from
+ * (left min element to current element) and (current element to right max element)
+ * the second part of the above eq can be achieved by coming from right to left
+ * for input [3,3,5,0,0,3,1,4]
+ * profit from l->r [0,0,2,2,2,3,3,4]
+ * profit from r->l [4,4,4,4,4,3,3,0]
+ * this simply states that at index 2 if we come from left the profit is 2
+ * and we can initiate another transaction to obtain another profit
+ */
+ public static int maxProfit(int[] prices) {
+ int[] profit1 = new int[prices.length];
+ int[] profit2 = new int[prices.length];
+
+ int min = prices[0];
+ for (int i = 1; i < prices.length; i++) {
+ min = Math.min(min, prices[i]);
+ profit1[i] = Math.max(profit1[i - 1], prices[i] - min);
+ }
+
+
+ int max = prices[prices.length - 1];
+
+ for (int i = prices.length - 2; i >= 0; i--) {
+ max = Math.max(max, prices[i]);
+ profit2[i] = Math.max(profit2[i + 1], max - prices[i]);
+ }
+ //at any pos 'i' profit1[i] denotes profit upto 0 to i
+ // at any pos 'i' profit2[i] denotes profit upto i+1 to n
+ int result = 0;
+ for (int i = 0; i < prices.length; i++) {
+ result = Math.max(result, profit2[i] + profit1[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Buy sell recursive template
+ */
+ public int maxProfitRecursive(int[] prices) {
+ Integer[][][] dp = new Integer[prices.length + 1][2][3];
+ return recursionHelper(prices, 0, 0, 2, dp);
+ }
+
+ public int recursionHelper(int[] prices, int idx, int canSell, int txn, Integer[][][] dp) {
+
+ if (txn == 0) return 0;
+ if (idx >= prices.length) return 0;
+ if (dp[idx][canSell][txn] != null) return dp[idx][canSell][txn];
+ if (canSell == 0) {
+ int buy = -prices[idx] + recursionHelper(prices, idx + 1, 1, txn, dp);
+ int notBuy = recursionHelper(prices, idx + 1, 0, txn, dp);
+ return dp[idx][canSell][txn] = Math.max(buy, notBuy);
+ } else {
+ int sell = prices[idx] + recursionHelper(prices, idx + 1, 0, txn - 1, dp);
+ int notSell = recursionHelper(prices, idx + 1, 1, txn, dp);
+ return dp[idx][canSell][txn] = Math.max(sell, notSell);
+ }
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/stocks/BuyAndSellWithTransactionFee.java b/src/main/java/dynamicProgramming/stocks/BuyAndSellWithTransactionFee.java
new file mode 100644
index 0000000..109229e
--- /dev/null
+++ b/src/main/java/dynamicProgramming/stocks/BuyAndSellWithTransactionFee.java
@@ -0,0 +1,48 @@
+package dynamicProgramming.stocks;
+
+/**
+ * https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee
+ */
+public class BuyAndSellWithTransactionFee {
+
+ public int maxProfit(int[] prices, int fee) {
+ if (prices == null || prices.length == 0) {
+ return 0;
+ }
+
+ int days = prices.length;
+ int[] buy = new int[days]; // the max profit in ith day when the last operation is buy
+ int[] sell = new int[days]; // the max profit in ith day when the last operation is sell
+
+ buy[0] = -prices[0];
+
+ for (int i = 1; i < days; i++) {
+ buy[i] = Math.max(buy[i - 1], sell[i - 1] - prices[i]);
+ sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i] - fee);
+ }
+
+ return sell[days - 1];
+ }
+
+ public int maxProfitRecursive(int[] prices, int fee) {
+ Integer[][] dp = new Integer[prices.length + 1][2];
+ return recursionHelper(prices, 0, 0, fee, dp);
+ }
+
+ public int recursionHelper(int[] prices, int idx, int canSell, int fee, Integer[][] dp) {
+
+ if (idx >= prices.length) return 0;
+ if (dp[idx][canSell] != null) return dp[idx][canSell];
+ if (canSell == 0) {
+
+ int buy = -prices[idx] + recursionHelper(prices, idx + 1, 1, fee, dp);
+ int notBuy = recursionHelper(prices, idx + 1, 0, fee, dp);
+ return dp[idx][canSell] = Math.max(buy, notBuy);
+ } else {
+ int sell = prices[idx] + recursionHelper(prices, idx + 1, 0, fee, dp) - fee;
+ int notSell = recursionHelper(prices, idx + 1, 1, fee, dp);
+ return dp[idx][canSell] = Math.max(sell, notSell);
+ }
+ }
+
+}
diff --git a/src/main/java/dynamicProgramming/stocks/StockBuySellKTransactions.java b/src/main/java/dynamicProgramming/stocks/StockBuySellKTransactions.java
new file mode 100644
index 0000000..c3d956b
--- /dev/null
+++ b/src/main/java/dynamicProgramming/stocks/StockBuySellKTransactions.java
@@ -0,0 +1,157 @@
+package dynamicProgramming.stocks;
+
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.LinkedList;
+
+/**
+ * Date 12/22/2015
+ *
+ * @author Tushar Roy
+ *
+ * Time complexity - O(number of transactions * number of days) Space
+ * complexity - O(number of transactions * number of days)
+ *
+ * https://leetcode.com/discuss/15153/a-clean-dp-solution-which-generalizes-to-k-transactions
+ * https://www.youtube.com/watch?v=Pw6lrYANjz4&t=1228s
+ */
+public class StockBuySellKTransactions {
+
+ public int maxProfit(int prices[], int K) {
+ if (K == 0 || prices.length == 0) {
+ return 0;
+ }
+ int[][] T = new int[K + 1][prices.length];
+
+ for (int i = 1; i < T.length; i++) {
+ int maxDiff = -prices[0];
+ for (int j = 1; j < T[0].length; j++) {
+ T[i][j] = Math.max(T[i][j - 1], prices[j] + maxDiff);
+ maxDiff = Math.max(maxDiff, T[i - 1][j] - prices[j]);
+ }
+ }
+
+ System.out.println(Arrays.deepToString(T));
+ printActualSolution(T, prices);
+ return T[K][prices.length - 1];
+ }
+
+ public int maxProfitSpaceEfficient(int k, int[] prices) {
+ int n = prices.length;
+ if (k >= n / 2) { //if k >= n/2, then you can make maximum number of transactions
+ int maxProfit = 0;
+ for (int i = 1; i < n; i++) {
+ if (prices[i] > prices[i - 1]) {
+ maxProfit += prices[i] - prices[i - 1];
+ }
+ }
+ return maxProfit;
+ }
+ int[] buy = new int[k + 1], sell = new int[k + 1];
+ Arrays.fill(buy, Integer.MIN_VALUE);
+ for (int price : prices) {
+ for (int i = 1; i <= k; i++) {
+ buy[i] = Math.max(buy[i], sell[i - 1] - price);
+ sell[i] = Math.max(sell[i], buy[i] + price);
+ }
+ }
+ return sell[k];
+ }
+
+ public int maxProfit(int k, int[] prices) {
+ int[][] dp = new int[k + 1][prices.length + 1];
+
+ int n = prices.length;
+ if (n <= 1) {
+ return 0;
+ }
+ if (k >= n / 2) { //if k >= n/2, then you can make maximum number of transactions
+ int maxProfit = 0;
+ for (int i = 1; i < n; i++) {
+ if (prices[i] > prices[i - 1]) {
+ maxProfit += prices[i] - prices[i - 1];
+ }
+ }
+ return maxProfit;
+ }
+
+ for (int i = 1; i <= k; i++) {
+ for (int priceDay = 1; priceDay <= prices.length; priceDay++) {
+
+ int notTransactingAtPriceDay = dp[i][priceDay - 1];
+
+ for (int m = 0; m < priceDay; m++) {
+ int transactionTillPriceDay = prices[priceDay - 1] - prices[m]; //[priceDay-1] because priceday begins at 1
+ /*
+ * previous transaction till m,
+ * because if we are buy at m '(prices[priceDay - 1] - prices[m])',
+ * we should've completed transaction till m 'dp[i - 1][m]'
+ */
+ int previousTransactionTillM = dp[i - 1][m];
+ int temp = Math.max(notTransactingAtPriceDay, transactionTillPriceDay + previousTransactionTillM);
+ dp[i][priceDay] = Math.max(dp[i][priceDay], temp);
+ }
+ }
+ }
+ return dp[k][prices.length];
+ }
+
+
+ public void printActualSolution(int T[][], int prices[]) {
+ int i = T.length - 1;
+ int j = T[0].length - 1;
+
+ Deque stack = new LinkedList<>();
+ while (true) {
+ if (i == 0 || j == 0) {
+ break;
+ }
+ if (T[i][j] == T[i][j - 1]) {
+ j = j - 1;
+ } else {
+ stack.addFirst(j);
+ int maxDiff = T[i][j] - prices[j];
+ for (int k = j - 1; k >= 0; k--) {
+ if (T[i - 1][k] - prices[k] == maxDiff) {
+ i = i - 1;
+ j = k;
+ stack.addFirst(j);
+ break;
+ }
+ }
+ }
+ }
+
+ while (!stack.isEmpty()) {
+ System.out.println("Buy at price " + prices[stack.pollFirst()]);
+ System.out.println("Sell at price " + prices[stack.pollFirst()]);
+ }
+
+ }
+ public int maxProfitRecursive(int k, int[] prices) {
+ Integer[][][] dp = new Integer[prices.length+1][2][k+1];
+ return recursionHelper(prices,0,0,k,dp);
+ }
+
+ public int recursionHelper(int[] prices, int idx,int canSell, int txn,Integer[][][] dp){
+ if(idx>=prices.length || txn==0 ) return 0;
+ if(dp[idx][canSell][txn]!=null) return dp[idx][canSell][txn];
+ if(canSell==0){
+
+ int buy = -prices[idx]+recursionHelper(prices,idx+1,1,txn,dp);
+ int notBuy = recursionHelper(prices,idx+1,0,txn,dp);
+ return dp[idx][canSell][txn]=Math.max(buy,notBuy);
+ }else{
+ int sell = prices[idx]+recursionHelper(prices,idx+1,0,txn-1,dp);
+ int notSell = recursionHelper(prices,idx+1,1,txn,dp);
+ return dp[idx][canSell][txn]=Math.max(sell,notSell);
+ }
+ }
+
+ public static void main(String args[]) {
+ StockBuySellKTransactions sbt = new StockBuySellKTransactions();
+ int prices[] = {2, 5, 7, 1, 4, 3, 1, 3};
+
+ System.out.println("Max profit fast solution " + sbt.maxProfit(prices, 3));
+ }
+}
diff --git a/src/main/java/dynamicProgramming/stocks/StockBuySellWithCoolDown.java b/src/main/java/dynamicProgramming/stocks/StockBuySellWithCoolDown.java
new file mode 100644
index 0000000..2e3595e
--- /dev/null
+++ b/src/main/java/dynamicProgramming/stocks/StockBuySellWithCoolDown.java
@@ -0,0 +1,82 @@
+package dynamicProgramming.stocks;
+
+public class StockBuySellWithCoolDown {
+
+ public int maxProfit(int[] prices) {
+
+ if (prices == null || prices.length < 2) return 0;
+ int buy = 0, sell = -prices[0], rest = 0;
+
+ // Assume the buy, sell and rest are states
+ // the transistions would be
+ // 1) from Rest you have to come to buy
+ // 2) from buy you can rest/hold or you can sell
+ // 3) from sell you can hold or sell and go to Rest
+
+ // state 1=> first transistion max(buy, rest) we can either buy or rest at this point
+ // state 2=> we can either hold what was there in previous state or buy so '-' price[i]
+ // state 3=> to come to rest we have to sell and make profit so only the '+' sign
+
+ for (int i = 1; i < prices.length; i++) {
+ int tmp = buy;
+ buy = Math.max(buy, rest);
+ rest = sell + prices[i];
+ sell = Math.max(sell, tmp - prices[i]);
+ }
+ return Math.max(buy, rest);
+ }
+
+ /**
+ * cooldown[i] = max(cooldown[i - 1], sell[i - 1]); // Stay at cooldown, or rest from sell
+ * proceed to buy, ie, we have no stock now, and the max profit should be ''last no stock profit'' or ''last rest profit''
+ *
+ * buy[i] = max(buy[i - 1], cooldown[i - 1] - prices[i]); // Stay at buy, or buy from cooldown
+ * //can proceed to sell, ie, we now have stock, and the profit should be ''last stock profit'' or ''last no stock but buy this time''
+ *
+ * sell[i] = buy[i - 1] + prices[i]; // Only one way from s1
+ * //we should sell then take a rest
+ */
+ public int maxProfitExtraSpace(int[] prices) {
+
+ int n = prices.length;
+ int[] buy = new int[prices.length + 1];
+ int[] sell = new int[prices.length + 1];
+
+ buy[1] = -prices[0];
+ sell[1] = 0;
+ if (n == 1) {
+ return sell[0];
+ }
+
+ for (int i = 2; i <= n; i++) {
+ buy[i] = Math.max(buy[i - 1], sell[i - 2] - prices[i - 1]);
+
+ sell[i] = Math.max(sell[i - 1], buy[i - 1] + prices[i - 1]);
+ }
+ return sell[n];
+
+ }
+
+ public static void main(String[] args) {
+ new StockBuySellWithCoolDown().maxProfitExtraSpace(new int[]{1, 2, 3, 0, 2});
+ }
+
+ public int maxProfitRecursive(int[] prices) {
+ Integer[][] dp = new Integer[prices.length][2];
+ return recursionHelper(prices, 0, 0, dp);
+ }
+
+ public int recursionHelper(int[] prices, int idx, int canSell, Integer[][] dp) {
+ if (idx >= prices.length) return 0;
+ if (dp[idx][canSell] != null) return dp[idx][canSell];
+ if (canSell == 0) {
+ int buy = -prices[idx] + recursionHelper(prices, idx + 1, 1, dp);
+ int notBuy = recursionHelper(prices, idx + 1, 0, dp);
+ return dp[idx][canSell] = Math.max(buy, notBuy);
+ } else {
+ int sell = prices[idx] + recursionHelper(prices, idx + 2, 0, dp);
+ int notSell = recursionHelper(prices, idx + 1, 1, dp);
+ return dp[idx][canSell] = Math.max(sell, notSell);
+ }
+ }
+}
diff --git a/src/main/java/dynamicProgramming/unboundedknapsack/CuttingRod.java b/src/main/java/dynamicProgramming/unboundedknapsack/CuttingRod.java
new file mode 100644
index 0000000..3b3b8e9
--- /dev/null
+++ b/src/main/java/dynamicProgramming/unboundedknapsack/CuttingRod.java
@@ -0,0 +1,80 @@
+package dynamicProgramming.unboundedknapsack;
+
+import java.util.Arrays;
+
+/**
+ * https://leetcode.com/problems/minimum-cost-to-cut-a-stick
+ * https://www.youtube.com/watch?v=xwomavsC86c
+ */
+public class CuttingRod {
+
+ public int minCost(int n, int[] cuts) {
+ int len = cuts.length + 2;
+
+ int[] endpoints = new int[len];
+ endpoints[0] = 0;
+ for (int i = 1; i < len - 1; i++) endpoints[i] = cuts[i - 1];
+ endpoints[len - 1] = n;
+ Arrays.sort(endpoints);
+
+
+ int[][] dp = new int[len][len];
+
+ // d : dist between i & j, the starting & ending position of stick
+ for (int d = 2; d < len; d++) {
+ for (int i = 0, j = i + d; j < len; i++, j++) {
+ dp[i][j] = Integer.MAX_VALUE;
+
+ int curr = endpoints[j] - endpoints[i];
+ for (int k = i + 1; k < j; k++) {
+ dp[i][j] = Math.min(dp[i][j], dp[i][k] + dp[k][j] + curr);
+ }
+ }
+ }
+ return dp[0][len - 1];
+ }
+
+ /**
+ * The algorithm is quite Brute Force, we would try to generate all possible permutations of cuts,
+ * and would try to know what permutation would lead to best result, i.e. minimize our cost for cutting.
+ *
+ * Let us suppose we are currently having a wood piece from index l to index r (i.e. the length of the wood is r - l, indexing is done as illustrated in the problem).
+ * Now, we try every possible cut that we could perform in the range from l to r.
+ *
+ * Since a cut (let's say, cut is at i index) results in our original piece to further split into 2 parts (one from [l, i], and second from [i, r]).
+ * Also, lets suppose the minimum cost of cutting, the segment [l, i] is minLeft and similarly for [i, r] is minRight.
+ * Hence the cost to cut the rod segment [l, r] would be cost_i = minLeft + minRight + (r - l) (r - l is the cost to perform the cut at i).
+ * Similarly, a cut at j index would cost in total, say, cost_j, similarly at k be cost_k and so on...
+ *
+ * The minimum cost to cut the rod from index l to r hence would be min(cost_i, cost_j, cost_k, ...).
+ */
+ public int minCostRecursive(int n, int[] cuts) {
+ Integer[][] dp = new Integer[101][101];
+ int[] cutsWithLengthOfRodAppendedToEnds = Arrays.copyOf(cuts, cuts.length + 2);
+ cutsWithLengthOfRodAppendedToEnds[cutsWithLengthOfRodAppendedToEnds.length - 1] = n;
+ Arrays.sort(cutsWithLengthOfRodAppendedToEnds);
+ return recursionHelper(cutsWithLengthOfRodAppendedToEnds, 1, cutsWithLengthOfRodAppendedToEnds.length - 2, dp);
+ }
+
+ public int recursionHelper(int[] cutsWithLengthOfRod, int i, int j, Integer[][] dp) {
+ if (i > j) return 0;
+ if (dp[i][j] != null) return dp[i][j];
+ int min = Integer.MAX_VALUE;
+
+ for (int mid = i; mid <= j; mid++) {
+
+ int cost = cutsWithLengthOfRod[j + 1] - cutsWithLengthOfRod[i - 1] + recursionHelper(cutsWithLengthOfRod, i, mid - 1, dp) +
+ recursionHelper(cutsWithLengthOfRod, mid + 1, j, dp);
+ min = Math.min(cost, min);
+ }
+
+ return dp[i][j] = min;
+
+ }
+
+ public static void main(String args[]) {
+ CuttingRod cr = new CuttingRod();
+ int[] price = {1, 5, 3, 6};
+ System.out.println(cr.minCost(9, price));
+ }
+}
\ No newline at end of file
diff --git a/src/geeksforgeeks/ArticulationPoint.java b/src/main/java/graph/ArticulationPoint.java
similarity index 99%
rename from src/geeksforgeeks/ArticulationPoint.java
rename to src/main/java/graph/ArticulationPoint.java
index 20df9d4..8710fce 100644
--- a/src/geeksforgeeks/ArticulationPoint.java
+++ b/src/main/java/graph/ArticulationPoint.java
@@ -1,4 +1,4 @@
-package geeksforgeeks;
+package graph;
import java.util.ArrayList;
import java.util.Collection;
diff --git a/src/main/java/graph/MinimumJumpsToReachHome.java b/src/main/java/graph/MinimumJumpsToReachHome.java
new file mode 100644
index 0000000..f204168
--- /dev/null
+++ b/src/main/java/graph/MinimumJumpsToReachHome.java
@@ -0,0 +1,57 @@
+package graph;
+
+import java.util.LinkedList;
+import java.util.Queue;
+
+//https://leetcode.com/problems/minimum-jumps-to-reach-home/description/
+public class MinimumJumpsToReachHome {
+ static class Pair {
+ int pos;
+ boolean dir;
+ public Pair(int pos, boolean dir) {
+ this.pos = pos;
+ this.dir = dir;
+ }
+ }
+ public int minimumJumps(int[] forbidden, int a, int b, int x) {
+ int limit = 2000 + 2 * b + 1; // could hardcode a value grater than given in the limit of the problem
+ boolean[] visited = new boolean[limit];
+ for (int num: forbidden) {
+ visited[num] = true;
+ }
+ int step = 0;
+ Queue q = new LinkedList<>();
+ q.add(new Pair(0, false));
+ visited[0] = true;
+ while (!q.isEmpty()) {
+ int size = q.size();
+ for (int i = 0; i < size; i++) {
+ Pair p = q.poll();
+ int pos = p.pos;
+ boolean dir = p.dir;
+
+ if (pos == x) return step;
+
+ if (!dir) {
+ int backward = pos - b;
+
+ if (backward > 0 && !visited[backward]) {
+ q.offer(new Pair(backward, true));
+ visited[backward] = true;
+ }
+ }
+
+ int forward = pos + a;
+
+ if (forward < limit && !visited[forward]) {
+ q.offer(new Pair(forward, false));
+ visited[forward] = true;
+ }
+
+
+ }
+ step++;
+ }
+ return -1;
+ }
+}
diff --git a/src/main/java/graph/adjacencyList/AdjacencyList.java b/src/main/java/graph/adjacencyList/AdjacencyList.java
new file mode 100644
index 0000000..5cbb663
--- /dev/null
+++ b/src/main/java/graph/adjacencyList/AdjacencyList.java
@@ -0,0 +1,47 @@
+
+package graph.adjacencyList;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class AdjacencyList {
+
+ public static void main(String[] args) {
+ List adjListArray[] = new LinkedList[5];
+ AdjacencyList list = new AdjacencyList();
+ list.add(1, 3, adjListArray);
+ list.add(1, 2, adjListArray);
+ list.add(2, 3, adjListArray);
+ list.add(3, 4, adjListArray);
+ list.add(4, 2, adjListArray);
+ list.add(5, 4, adjListArray);
+
+ list.printList(adjListArray);
+ }
+
+ private void printList(List[] adjListArray) {
+ for (int i = 0; i < adjListArray.length; i++) {
+ List list = adjListArray[i];
+ System.out.print((i + 1) + "-->");
+ boolean firstTime = true;
+ for (Integer val : list) {
+ if (!firstTime)
+ System.out.print(" - ");
+ else
+ firstTime = false;
+ System.out.print(val);
+ }
+ System.out.println();
+ }
+ }
+
+ private void add(int src, int dest, List[] adjListArray) {
+ int val = src - 1;
+ List list = adjListArray[val];
+ if (null == list)
+ list = new LinkedList();
+ list.add(dest);
+ adjListArray[val] = list;
+ }
+
+}
diff --git a/src/main/java/graph/adjacencyMatrix/AdjacencyMatrix.java b/src/main/java/graph/adjacencyMatrix/AdjacencyMatrix.java
new file mode 100644
index 0000000..0589973
--- /dev/null
+++ b/src/main/java/graph/adjacencyMatrix/AdjacencyMatrix.java
@@ -0,0 +1,42 @@
+package graph.adjacencyMatrix;
+
+public class AdjacencyMatrix {
+
+ public static void main(String[] args) {
+ AdjacencyMatrix am = new AdjacencyMatrix();
+
+ int[][] arr = new int[5][5];
+ am.add(1, 2, arr);
+ am.add(1, 5, arr);
+ am.add(1, 4, arr);
+ am.add(3, 2, arr);
+ am.add(5, 2, arr);
+ am.add(3, 4, arr);
+ am.add(4, 5, arr);
+
+ am.printMatrix(arr);
+ am.removeLink(3, 4, arr);
+ System.out.println("*******");
+ am.printMatrix(arr);
+
+ }
+
+ private void removeLink(int i, int j, int[][] arr) {
+ arr[i - 1][j - 1] = 0;
+ }
+
+ private void printMatrix(int[][] arr) {
+ for (int i = 0; i < arr.length; i++) {
+ for (int j = 0; j < arr.length; j++) {
+ System.out.print(arr[i][j] + " ");
+ }
+ System.out.println();
+ }
+
+ }
+
+ private void add(int i, int j, int[][] arr) {
+ arr[i - 1][j - 1] = 1;
+ }
+
+}
diff --git a/src/main/java/graph/bellmanFord/BellmanFord.java b/src/main/java/graph/bellmanFord/BellmanFord.java
new file mode 100644
index 0000000..ffda9d0
--- /dev/null
+++ b/src/main/java/graph/bellmanFord/BellmanFord.java
@@ -0,0 +1,56 @@
+package graph.bellmanFord;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BellmanFord {
+
+ private static int INFINITY = 10000000;
+
+ public static void main(String[] args) {
+ Graph graph = new Graph();
+ graph.addEdges(0, 1, 4);
+ graph.addEdges(0, 2, 5);
+ graph.addEdges(0, 3, 8);
+ graph.addEdges(1, 2, -3);
+ graph.addEdges(2, 4, 4);
+ graph.addEdges(3, 4, 2);
+ graph.addEdges(4, 3, 1);
+
+ BellmanFord bf = new BellmanFord();
+ Vertex startVertex = graph.vertexMap.values().iterator().next();
+ bf.shortestPath(graph, startVertex);
+ }
+
+ private void shortestPath(Graph graph, Vertex startVertex) {
+ Map, Integer> distance = new HashMap<>();
+ Map, Vertex> parent = new HashMap<>();
+
+ for (Vertex vertex : graph.vertexMap.values()) {
+ distance.put(vertex, BellmanFord.INFINITY);
+ parent.put(vertex, null);
+ }
+ distance.put(startVertex, 0);
+
+ for (int i = 0; i < graph.vertexMap.size() - 1; i++) {
+ for (Edge edge : graph.allEdges) {
+ int j = distance.get(edge.u) + edge.weight;
+ if (j < distance.get(edge.v)) {
+ distance.put(edge.v, j);
+ parent.put(edge.v, edge.u);
+ }
+ }
+ }
+
+ for (Edge edge : graph.allEdges) {
+ int j = distance.get(edge.u) + edge.weight;
+ if (j < distance.get(edge.v)) {
+ throw new NegativeException();
+ }
+ }
+ for (Map.Entry, Integer> map : distance.entrySet()) {
+ System.out.println(map.getKey().key + "-->" + map.getValue());
+ }
+ }
+
+}
diff --git a/src/main/java/graph/bellmanFord/Edge.java b/src/main/java/graph/bellmanFord/Edge.java
new file mode 100644
index 0000000..513013b
--- /dev/null
+++ b/src/main/java/graph/bellmanFord/Edge.java
@@ -0,0 +1,15 @@
+package graph.bellmanFord;
+
+public class Edge {
+
+ Vertex u;
+ Vertex v;
+ int weight;
+
+ public Edge(Vertex u, Vertex v, int weight) {
+ this.u = u;
+ this.v = v;
+ this.weight = weight;
+ }
+
+}
diff --git a/src/main/java/graph/bellmanFord/Graph.java b/src/main/java/graph/bellmanFord/Graph.java
new file mode 100644
index 0000000..517f46d
--- /dev/null
+++ b/src/main/java/graph/bellmanFord/Graph.java
@@ -0,0 +1,35 @@
+package graph.bellmanFord;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class Graph {
+
+ HashMap> vertexMap = new HashMap>();
+ List> allEdges = new ArrayList>();
+
+ public void addEdges(T u, T v, int weight) {
+ Vertex vertex1 = null;
+ if (vertexMap.containsKey(u)) {
+ vertex1 = vertexMap.get(u);
+ } else {
+ vertex1 = new Vertex(u);
+ vertexMap.put(u, vertex1);
+ }
+
+ Vertex vertex2 = null;
+ if (vertexMap.containsKey(v)) {
+ vertex2 = vertexMap.get(v);
+ } else {
+ vertex2 = new Vertex(v);
+ vertexMap.put(v, vertex2);
+ }
+
+ Edge edge = new Edge(vertex1, vertex2, weight);
+ allEdges.add(edge);
+
+ vertex1.addAdjacentVertex(vertex2, edge);
+ }
+
+}
diff --git a/src/main/java/graph/bellmanFord/NegativeException.java b/src/main/java/graph/bellmanFord/NegativeException.java
new file mode 100644
index 0000000..3010279
--- /dev/null
+++ b/src/main/java/graph/bellmanFord/NegativeException.java
@@ -0,0 +1,10 @@
+package graph.bellmanFord;
+
+public class NegativeException extends RuntimeException {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/src/main/java/graph/bellmanFord/Vertex.java b/src/main/java/graph/bellmanFord/Vertex.java
new file mode 100644
index 0000000..291b470
--- /dev/null
+++ b/src/main/java/graph/bellmanFord/Vertex.java
@@ -0,0 +1,20 @@
+package graph.bellmanFord;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class Vertex {
+ T key;
+ List> adjacentVertex = new ArrayList>();
+ List> edges = new ArrayList>();
+
+ public Vertex(T key) {
+ this.key = key;
+ }
+
+ public void addAdjacentVertex(Vertex vertex2, Edge edge) {
+ adjacentVertex.add(vertex2);
+ edges.add(edge);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/graph/breadthFirstSearch/BreadthFirstSearch.java b/src/main/java/graph/breadthFirstSearch/BreadthFirstSearch.java
new file mode 100644
index 0000000..e07c57a
--- /dev/null
+++ b/src/main/java/graph/breadthFirstSearch/BreadthFirstSearch.java
@@ -0,0 +1,53 @@
+package graph.breadthFirstSearch;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+
+public class BreadthFirstSearch {
+
+ public static void main(String[] args) {
+ BreadthFirstSearch bfs = new BreadthFirstSearch();
+ Graph graph = new Graph(5);
+ bfs.addEdges(1, 2, graph);
+ bfs.addEdges(2, 3, graph);
+ bfs.addEdges(3, 4, graph);
+ bfs.addEdges(4, 5, graph);
+ bfs.addEdges(2, 4, graph);
+ bfs.addEdges(1, 5, graph);
+
+ bfs.print(1, graph);
+
+ }
+
+ private void print(int i, Graph graph) {
+ Queue queue = new LinkedList();
+ queue.add(i);
+ Queue clone = new LinkedList(queue);
+ exploreVertex(queue, clone, graph);
+
+ for (Integer val : clone) {
+ System.out.print(val + 1 + "->");
+ }
+ }
+
+ private void exploreVertex(Queue queue, Queue clone, Graph graph) {
+ while (!queue.isEmpty()) {
+ Integer poll = queue.poll();
+ List list = graph.adjacentList[poll];
+ for (Integer value : list) {
+ if (!clone.contains(value)) {
+ clone.add(value);
+ queue.add(value);
+ }
+ }
+ }
+ }
+
+ private void addEdges(int src, int dest, Graph graph) {
+ int srcVal = src - 1;
+ int destVal = dest - 1;
+ graph.adjacentList[srcVal].add(destVal);
+ graph.adjacentList[destVal].add(srcVal);
+ }
+}
diff --git a/src/main/java/graph/breadthFirstSearch/Graph.java b/src/main/java/graph/breadthFirstSearch/Graph.java
new file mode 100644
index 0000000..4b5b3c5
--- /dev/null
+++ b/src/main/java/graph/breadthFirstSearch/Graph.java
@@ -0,0 +1,18 @@
+package graph.breadthFirstSearch;
+
+import java.util.LinkedList;
+import java.util.List;
+
+public class Graph {
+
+ List adjacentList[];
+ int vertices;
+
+ public Graph(int v) {
+ vertices = v;
+ adjacentList = new LinkedList[vertices];
+ for (int i = 0; i < adjacentList.length; i++) {
+ adjacentList[i] = new LinkedList<>();
+ }
+ }
+}
diff --git a/src/main/java/graph/cycle/CycleInDirectedGraph.java b/src/main/java/graph/cycle/CycleInDirectedGraph.java
new file mode 100644
index 0000000..2e823e9
--- /dev/null
+++ b/src/main/java/graph/cycle/CycleInDirectedGraph.java
@@ -0,0 +1,67 @@
+package graph.cycle;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * http://www.geeksforgeeks.org/detect-cycle-in-a-graph/
+ */
+public class CycleInDirectedGraph {
+
+ public boolean hasCycle(Graph graph) {
+ Set> whiteSet = new HashSet<>();
+ Set> graySet = new HashSet<>();
+ Set