├── Arrays ├── Equilibrium_Point.java ├── First_Missing_Positive.java ├── Largest_Number_From_Array.java ├── Minimum_Platforms.java ├── Move_Zeroes.java ├── Rotate_Image.java ├── Sort_Array_Of_0_1_2.java ├── Spiral_Traversal_Of_Matrix.java ├── Stock_Buy_Sell.java └── Zig_Zag_Array.java ├── Backtracking ├── CombinationSum.java ├── CombinationSumII.java ├── CombinationSumIII.java ├── GenerateParentheses.java ├── LetterCasePermutation.java ├── PalindromePartitioning.java ├── Permutations.java ├── PermutationsII.java ├── Subsets.java ├── SubsetsII.java └── WordSearch.java ├── BinarySearch ├── Binary_Search_Notes.txt ├── Binary_Search_Variants.java ├── Count_Negative_Numbers_in_a_Sorted_Matrix.java ├── Find_Minimum in_Rotated_Sorted_Array.java ├── Find_Peak_Element.java ├── First_Bad_Version.java ├── Guess_Number_Higher_or_Lower.java ├── Peak_Index_in_a_Mountain_Array.java ├── Search_Insert_Position.java ├── Search_in_Rotated_Sorted_Array.java └── Sqrt(x).java ├── DynamicProgramming ├── #BinaryStringsWithoutConsecutive1s.java ├── #PathsInMatrixWithGivenCost.java ├── #SolutionsOfLinearEqtn.java ├── 0-1KnapsackProblem.java ├── Boolean_Parenthesization_Problem.java ├── BoxStackingProblem.java ├── CoinChangeWays │ └── CoinChangeNumberOfWays.java ├── CountNumberOfWaysToCoverADistance.java ├── DiceThrow │ └── DiceThrow.java ├── EditDistance.java ├── EggDroppingPuzzle.java ├── ImplementDiffUtility.java ├── KadaneMaximumSumSubarray.java ├── LargestSquareSubMatrixOf1.java ├── LongestBitonicSubsequence │ ├── LengthOfLongestBitonicSubsequence.java │ └── PrintLongestBitonicSubsequence.java ├── LongestCommonSubsequence │ ├── Find_Longest_Common_Subsequence.java │ └── Length_Of_Longest_Common_Subsequence.java ├── LongestCommonSubstring │ ├── Find_Longest_Common_Substring.java │ └── Length_Of_Longest_Common_Substring.java ├── LongestIncreasingPathInMatrix.java ├── LongestIncreasingPathInMatrix │ └── LongestIncreasingPathInMatrix.java ├── LongestIncreasingSubsequence │ ├── Find_Longest_Increasing_Subsequence.java │ └── Length_Of_Longest_Increasing_Subsequence.java ├── LongestPalindromicSubsequence │ └── LengthOfLongestPalindromicSubseq.java ├── LongestPalindromicSubstring.java ├── LongestPathInMatrixconstraints │ └── LongestPathInMatrixWithConstraints.java ├── LongestRepeatedSubsequenceProblem.java ├── MIT-6.006-IntroToAlgosNotes │ ├── DP1_Fibonacci_ShortestPaths.java │ ├── DP2_Text_Justification_Blackjack.java │ ├── DP3_Parenthesization_EditDistance_Knapsack.java │ └── DP4_GuitarFingering_Tetris_SuperMarioBros.java ├── MatrixChainMultiplication │ └── MatrixChainMultiplication.java ├── MaxRectangularSubmatrixOf1s.java ├── MaximumProductCutting.java ├── MaximumSumIncreasingSubsequence │ ├── MaxSumIncreasingSubseq.java │ └── PrintMaxSumIncreasingSubseq.java ├── MaximumSumOfSubseqNonAdjacent.java ├── MaximumSumRectangularSubMatrix.java ├── MaximumSumSubMatrixInAGivenMatrix.java ├── MinCostToReachLastCellFromFirstCellMatrix.java ├── MinimumCutsForPalindromicPartition.java ├── MinimumSumPartition │ └── MinimumSumPartition.java ├── OptimalStratergyForGame │ ├── Optimal_Stratergy_For_Game.java │ └── Optimal_Stratergy_For_Game2.java ├── PartitionProblem │ └── PartitionProblem[ReturnBoolean].java ├── RodCuttingProblem.java ├── ShortestCommonSupersequence │ ├── LengthOfShortestCommonSupersequence.java │ └── PrintShortestCommonSupersequence.java ├── StringInterleaving.java ├── SubsetSumProblem │ └── SubsetSumProblem.java ├── SumOfElementsInASubMatrixConstantTime │ └── SumOfAllElementsInASubMatrixInConstantTime.java ├── WildCardMatching.java └── WordBreakProblem │ ├── WordBreakBoolean.java │ ├── WordBreakPrintWords.java │ └── [Optimized]WordBreakPrintWords.java ├── Google-Code-Jam-QualificationRound-2020 ├── NestingDepth.java ├── ParentingPartneringReturns.java └── Vestigium.java ├── Google_Hash_Code_2020.java ├── GraphsDFS&BFS ├── Alien_Dictionary_Topological_Sort.java ├── Binary_Tree_Level_Order_Traversal.java ├── Clone_Graph.java ├── Course_Schedule.java ├── Course_Schedule_II.java ├── DelayedProjects.java ├── Find_the_Town_Judge.java ├── Flower_Planting_With_No_Adjacent.java ├── Friend_Circles.java ├── KahnTopologicalSort.java ├── Number_of_Islands.java └── TopologicalSort_DFS.java ├── Hash Table └── Two_Sum.java ├── LinkedList ├── Add_Two_Numbers.java ├── MergeTwoSortedLists.java ├── RemoveNthNodeFromEndOfList.java └── Remove_Nth_Node_From_End_of_List.java ├── Math └── Palindrome_Number.java ├── README.md ├── Recursion └── LetterCombinationsOfAPhoneNumber.java ├── Remove duplicate lines from Text file └── remove_duplicate_lines.py ├── SlidingWindow ├── Find_All_Anagarms_In_A_String.java ├── Longest_Repeating_Character_Replacement.java ├── Longest_Substring_With_Atmost_Two_Distinct_Characters.java ├── Longest_Substring_Without_Repeating_Characters.java ├── Minimum_Window_Substring.java └── Permutation_in_String.java ├── Stacks ├── Decode_String.java └── ValidParentheses.java ├── String ├── DoorMat.py ├── LongestCommonPrefix.java ├── What's your name.py ├── ZigZag_Conversion.java └── sWAPcASE.py ├── Trees ├── Kth_Smallest_Element_in_a_BST.java ├── N_aryTreeLevelorderTraversal.java ├── N_aryTreePostorderTraversal.java ├── N_aryTreePreorderTraversal.java ├── Same_Tree.java ├── Symmetric_Tree.java └── Validate_Binary_Search_Tree.java ├── TwoPointer ├── 3Sum.java ├── 3SumClosest.java ├── 4Sum.java └── ContainerWithMostWater.java └── strStr().java /Arrays/Equilibrium_Point.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.lang.*; 3 | import java.io.*; 4 | class GFG 5 | { 6 | public static void main (String[] args) 7 | { 8 | //code 9 | Scanner s = new Scanner(System.in); 10 | int t = s.nextInt(); 11 | 12 | while(t-- > 0){ 13 | int n = s.nextInt(); 14 | int a[] = new int[n]; 15 | 16 | int rightSum = 0; 17 | for(int i = 0 ; i < n ; i++){ 18 | a[i] = s.nextInt(); 19 | rightSum += a[i]; 20 | } 21 | 22 | if(n == 1){ 23 | System.out.println(1); 24 | continue; 25 | } 26 | 27 | int leftSum = 0; 28 | boolean flag = false; 29 | 30 | for(int i = 0 ; i < n ; i++){ 31 | rightSum -= a[i]; 32 | 33 | if(leftSum == rightSum){ 34 | System.out.println(i+1); 35 | flag = true; 36 | break; 37 | } 38 | 39 | leftSum += a[i]; 40 | } 41 | 42 | if(!flag) System.out.println(-1); 43 | 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Arrays/First_Missing_Positive.java: -------------------------------------------------------------------------------- 1 | //Leetcode 41. First Missing Positive 2 | //Question - https://leetcode.com/problems/first-missing-positive/ 3 | 4 | /*Given an unsorted integer array, find the smallest missing positive integer. 5 | 6 | Example 1: 7 | 8 | Input: [1,2,0] 9 | Output: 3 10 | 11 | Example 2: 12 | 13 | Input: [3,4,-1,1] 14 | Output: 2 15 | 16 | Example 3: 17 | 18 | Input: [7,8,9,11,12] 19 | Output: 1 20 | 21 | Note: 22 | 23 | Your algorithm should run in O(n) time and uses constant extra space. 24 | */ 25 | 26 | class Solution { 27 | public int firstMissingPositive(int[] nums) { 28 | if(nums==null || nums.length==0) return 1; 29 | 30 | boolean oneFound = false; 31 | for(int i=0;i=0 && targetIndex0) return (i+1); 47 | } 48 | return nums.length+1; 49 | 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Arrays/Largest_Number_From_Array.java: -------------------------------------------------------------------------------- 1 | class Solution { 2 | public String largestNumber(int[] nums) { 3 | if(nums.length == 0) return ""; 4 | else if(nums.length == 1) return String.valueOf(nums[0]); 5 | 6 | String arr[] = new String[nums.length]; 7 | 8 | for(int i = 0 ; i < nums.length ; i++){ 9 | arr[i] = String.valueOf(nums[i]); 10 | } 11 | 12 | Comparator comp = new Comparator(){ 13 | public int compare(String s1, String s2){ 14 | String a = s1+s2; 15 | String b = s2+s1; 16 | 17 | //descending order 18 | return b.compareTo(a); 19 | } 20 | }; 21 | 22 | Arrays.sort(arr, comp); 23 | if(arr[0].charAt(0) == '0') return "0"; 24 | 25 | StringBuffer sb = new StringBuffer(""); 26 | for(String s : arr){ 27 | sb.append(s); 28 | } 29 | 30 | return String.valueOf(sb); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Arrays/Minimum_Platforms.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.lang.*; 3 | import java.io.*; 4 | class GFG 5 | { 6 | public static void main (String[] args) 7 | { 8 | //code 9 | Scanner s = new Scanner(System.in); 10 | int t = s.nextInt(); 11 | 12 | while(t-- > 0){ 13 | int n = s.nextInt(); 14 | 15 | int arr[] = new int[n]; 16 | for(int i = 0 ; i < n ; i++){ 17 | arr[i] = s.nextInt(); 18 | } 19 | 20 | int dept[] = new int[n]; 21 | for(int i = 0 ; i < n ; i++){ 22 | dept[i] = s.nextInt(); 23 | } 24 | 25 | Arrays.sort(arr); 26 | Arrays.sort(dept); 27 | 28 | int i = 1; 29 | int j = 0; 30 | int plat = 1; 31 | int res = 1; 32 | 33 | while(i < n && j < n){ 34 | //if current arrival time is smaller than previous departure 35 | //time then, move to the next arrival time to see if that 36 | //too is smaller than previous departure time. 37 | if(arr[i] <= dept[j]){ 38 | plat++; 39 | i++; 40 | } 41 | //If current arrival time is greater than previous departure 42 | //time then, move to next departure time to see if that 43 | //arrival time is greater than next departure too or not 44 | else{ 45 | plat--; 46 | j++; 47 | } 48 | 49 | res = Math.max(res, plat); 50 | } 51 | 52 | System.out.println(res); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Arrays/Move_Zeroes.java: -------------------------------------------------------------------------------- 1 | //https://leetcode.com/problems/move-zeroes/ 2 | 3 | class Solution { 4 | public void moveZeroes(int[] nums) { 5 | int cnt = 0; 6 | int index = 0; 7 | for(int i=0 ; i < nums.length ; i++){ 8 | if(nums[i] == 0) cnt++; 9 | else{ 10 | nums[index] = nums[i]; 11 | index++; 12 | } 13 | 14 | } 15 | 16 | for(int i=nums.length-1 ; i>=nums.length - cnt ; i--){ 17 | nums[i] = 0; 18 | } 19 | 20 | for(int i=0 ; i < nums.length ; i++) System.out.print(nums[i]+" "); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Arrays/Sort_Array_Of_0_1_2.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.lang.*; 3 | import java.io.*; 4 | class GFG 5 | { 6 | public static void main (String[] args) 7 | { 8 | //code 9 | Scanner s = new Scanner(System.in); 10 | int t = s.nextInt(); 11 | 12 | while(t-- > 0){ 13 | int n = s.nextInt(); 14 | int a[] = new int[n]; 15 | 16 | for(int i = 0 ; i < n ; i++){ 17 | a[i] = s.nextInt(); 18 | } 19 | 20 | int low = 0; 21 | int mid = 0; 22 | int high = n-1; 23 | int temp = -1; 24 | 25 | while(mid <= high){ 26 | switch(a[mid]){ 27 | case 0: 28 | temp = a[low]; 29 | a[low] = a[mid]; 30 | a[mid] = temp; 31 | low++; 32 | mid++; 33 | break; 34 | case 1: 35 | mid++; 36 | break; 37 | case 2: 38 | temp = a[high]; 39 | a[high] = a[mid]; 40 | a[mid] = temp; 41 | high--; 42 | break; 43 | } 44 | } 45 | 46 | for(int i=0;i 0){ 11 | int rows = s.nextInt(); 12 | int cols = s.nextInt(); 13 | 14 | int mat[][] = new int[rows][cols]; 15 | 16 | for(int i = 0 ; i < rows ; i++){ 17 | for(int j = 0 ; j < cols ; j++){ 18 | mat[i][j] = s.nextInt(); 19 | } 20 | } 21 | 22 | int startRow = 0, startCol = 0, endRow = rows-1, endCol = cols-1; 23 | while(startRow <= endRow && startCol <= endCol){ 24 | for(int i = startCol ; i <= endCol ; i++){ 25 | System.out.print(mat[startRow][i] + " "); 26 | } 27 | startRow++; 28 | 29 | for(int i = startRow ; i <= endRow ; i++){ 30 | System.out.print(mat[i][endCol] + " "); 31 | } 32 | endCol--; 33 | 34 | if(startRow <= endRow){ 35 | for(int i = endCol ; i >= startCol ; i--){ 36 | System.out.print(mat[endRow][i] + " "); 37 | } 38 | endRow--; 39 | } 40 | if(startCol <= endCol){ 41 | for(int i = endRow ; i >= startRow ; i--){ 42 | System.out.print(mat[i][startCol] + " "); 43 | } 44 | startCol++; 45 | } 46 | } 47 | 48 | System.out.println(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Arrays/Stock_Buy_Sell.java: -------------------------------------------------------------------------------- 1 | import java.util.*; 2 | import java.lang.*; 3 | import java.io.*; 4 | class GFG{ 5 | public static void main (String[] args){ 6 | //code 7 | Scanner s = new Scanner(System.in); 8 | int t = s.nextInt(); 9 | 10 | while(t-- > 0){ 11 | int n = s.nextInt(); 12 | int arr[] = new int[n]; 13 | 14 | for(int i = 0 ; i < n ; i++){ 15 | arr[i] = s.nextInt(); 16 | } 17 | 18 | List buy = new ArrayList<>(); 19 | List sell = new ArrayList<>(); 20 | 21 | int stocks = 0; 22 | int i = 0; 23 | while(i <= n-2){ //we 24 | while(i < n-1 && arr[i] >= arr[i+1]){ 25 | i++; 26 | } 27 | 28 | if(i == n-1) break; 29 | 30 | buy.add(i++); 31 | 32 | while(i < n && arr[i] >= arr[i-1]){ 33 | i++; 34 | } 35 | 36 | sell.add(i-1); 37 | 38 | stocks++; 39 | } 40 | 41 | if(stocks == 0) System.out.println("No Profit"); 42 | else{ 43 | for(i = 0 ; i < buy.size() ; i++){ 44 | System.out.print("(" + buy.get(i) + " " + sell.get(i) + ") "); 45 | } 46 | System.out.println(); 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Arrays/Zig_Zag_Array.java: -------------------------------------------------------------------------------- 1 | import java.lang.*; 2 | import java.io.*; 3 | class GFG 4 | { 5 | public static void main (String[] args) 6 | { 7 | //code 8 | Scanner s = new Scanner(System.in); 9 | int t = s.nextInt(); 10 | 11 | while(t-- > 0){ 12 | int n = s.nextInt(); 13 | 14 | int a[] = new int[n]; 15 | for(int i = 0 ; i < n ; i++){ 16 | a[i] = s.nextInt(); 17 | } 18 | 19 | for(int i = 1 ; i < n ; i++){ 20 | if(i%2 != 0){ 21 | if(a[i] < a[i-1]){ 22 | int temp = a[i]; 23 | a[i] = a[i-1]; 24 | a[i-1] = temp; 25 | } 26 | } 27 | else{ 28 | if(a[i] > a[i-1]){ 29 | int temp = a[i]; 30 | a[i] = a[i-1]; 31 | a[i-1] = temp; 32 | } 33 | } 34 | } 35 | 36 | for(int i = 0 ; i < n ; i++){ 37 | System.out.print(a[i] + " "); 38 | } 39 | System.out.println(); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Backtracking/CombinationSum.java: -------------------------------------------------------------------------------- 1 | //LeetCode 39. Combination Sum 2 | //Question - https://leetcode.com/problems/combination-sum/ 3 | 4 | class Solution { 5 | public List> combinationSum(int[] nums, int target) { 6 | List> res = new ArrayList<>(); 7 | helper(nums, 0, 0, target, new ArrayList<>(), res); 8 | return res; 9 | } 10 | 11 | public void helper(int nums[], int index, int sum, int target, List l, List> res){ 12 | if(sum > target) return; 13 | else if(sum == target){ 14 | res.add(new ArrayList<>(l)); 15 | return; 16 | } 17 | 18 | for(int i = index ; i < nums.length ; i++){ 19 | 20 | l.add(nums[i]); 21 | helper(nums, i, sum + nums[i], target, l, res); 22 | l.remove(l.size()-1); 23 | } 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Backtracking/CombinationSumII.java: -------------------------------------------------------------------------------- 1 | //LeetCode 40. Combination Sum II 2 | //Question - https://leetcode.com/problems/combination-sum-ii/ 3 | 4 | class Solution { 5 | public List> combinationSum2(int[] nums, int target) { 6 | List> res = new ArrayList<>(); 7 | 8 | Arrays.sort(nums); 9 | helper(nums, 0, 0, target, new ArrayList<>(), res); 10 | return res; 11 | 12 | } 13 | 14 | public void helper(int nums[], int index, int sum, int target, List l, List> res){ 15 | if(sum > target) return; 16 | else if(sum == target){ 17 | res.add(new ArrayList<>(l)); 18 | return; 19 | } 20 | 21 | for(int i = index ; i < nums.length ; i++){ 22 | if(i > index && nums[i] == nums[i-1]) continue; 23 | 24 | l.add(nums[i]); 25 | helper(nums, i + 1, sum + nums[i], target, l, res); 26 | l.remove(l.size()-1); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Backtracking/CombinationSumIII.java: -------------------------------------------------------------------------------- 1 | //LeetCode 216. Combination Sum III 2 | //Question - https://leetcode.com/problems/combination-sum-iii/ 3 | 4 | class Solution { 5 | //k ==> size of each combination 6 | //n ==> target sum of each combination 7 | //numbers from [1..9] can be used only once. 8 | 9 | public List> combinationSum3(int k, int n) { 10 | List> res = new ArrayList<>(); 11 | helper(k, n, 1, 0, new ArrayList<>(), res); 12 | 13 | return res; 14 | } 15 | 16 | public void helper(int k, int n, int num, int sum, List l, List> res){ 17 | //Check for the base condition 18 | if(l.size() == k && sum == n){ 19 | res.add(new ArrayList<>(l)); 20 | return; 21 | } 22 | 23 | //to avoid useless recursion 24 | else if(l.size() == k || sum > n) return; 25 | 26 | for(int i = num ; i <= 9 ; i++){ 27 | //make a decision 28 | l.add(i); 29 | 30 | helper(k, n, i + 1, sum + i, l, res); 31 | 32 | //backtrack 33 | l.remove(l.size()-1); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Backtracking/GenerateParentheses.java: -------------------------------------------------------------------------------- 1 | //LeetCode 22. Generate Parentheses 2 | //Question - https://leetcode.com/problems/generate-parentheses/ 3 | 4 | class Solution { 5 | public List generateParenthesis(int n) { 6 | List res = new ArrayList<>(); 7 | helper("", res, 0, 0, n); 8 | return res; 9 | } 10 | 11 | public void helper(String str, List l, int open, int close, int n){ 12 | if(str.length() == n*2){ 13 | l.add(str); 14 | return; 15 | } 16 | 17 | //each valid parentheses must have n open braces and not more. 18 | if(open < n) helper(str + '(', l, open + 1, close, n); 19 | //To maintain a valid parentheses, the closed brackets can only be added when 20 | //we have corresponding open brackets available. 21 | if(close < open) helper(str + ')', l, open, close + 1, n); 22 | } 23 | } -------------------------------------------------------------------------------- /Backtracking/LetterCasePermutation.java: -------------------------------------------------------------------------------- 1 | //LeetCode 784. Letter Case Permutation 2 | //Question - https://leetcode.com/problems/letter-case-permutation/ 3 | 4 | class Solution { 5 | public List letterCasePermutation(String S) { 6 | List res = new ArrayList<>(); 7 | helper(S, "", 0, res); 8 | return res; 9 | } 10 | 11 | public void helper(String inputString, String newString, int index, List l){ 12 | //base condition 13 | if(inputString.length() == newString.length()){ 14 | l.add(newString); 15 | return; 16 | } 17 | 18 | //check if current char is a number or alphabet 19 | char currChar = inputString.charAt(index); 20 | if(Character.isDigit(currChar)){ 21 | helper(inputString, newString + currChar, index + 1, l); 22 | } 23 | else{ 24 | //considering lower case 25 | helper(inputString, newString + Character.toLowerCase(currChar), index + 1, l); 26 | 27 | //considering upper case 28 | helper(inputString, newString + Character.toUpperCase(currChar), index + 1, l); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Backtracking/PalindromePartitioning.java: -------------------------------------------------------------------------------- 1 | //LeetCode 131. Palindrome Partitioning 2 | //Question - https://leetcode.com/problems/palindrome-partitioning/ 3 | 4 | class Solution { 5 | public List> partition(String s) { 6 | List> res = new ArrayList<>(); 7 | helper(s, 0, new ArrayList(), res); 8 | return res; 9 | } 10 | 11 | public void helper(String s, int index, List l, List> res){ 12 | //Base condition 13 | if(index == s.length()){ 14 | res.add(new ArrayList<>(l)); 15 | return; 16 | } 17 | 18 | //starting from each index, evaluate substrings of all lengths. Check if each 19 | //substring is a palindrome or not. If it is a palindrome, go deeper into 20 | //recursion to see if it is possible to break down the remaining string into 21 | //palindromic substrings or not. 22 | for(int i = index ; i < s.length() ; i++){ 23 | //check if the current substring is a palindrome or not 24 | if(isPalin(s, index, i)){ 25 | 26 | //make a partition 27 | l.add(s.substring(index, i+1)); 28 | 29 | helper(s, i+1, l, res); 30 | 31 | //backtrack - undo the partition 32 | l.remove(l.size()-1); 33 | } 34 | } 35 | } 36 | 37 | public boolean isPalin(String s, int start, int end){ 38 | while(start < end){ 39 | if(s.charAt(start++) != s.charAt(end--)) return false; 40 | } 41 | 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Backtracking/Permutations.java: -------------------------------------------------------------------------------- 1 | //LeetCode 46. Permutation 2 | //Question - https://leetcode.com/problems/permutations/ 3 | 4 | class Solution { 5 | public List> permute(int[] nums) { 6 | List> res = new ArrayList<>(); 7 | boolean visit[] = new boolean[nums.length]; 8 | 9 | helper(nums, visit, new ArrayList<>(), res); 10 | return res; 11 | } 12 | 13 | public void helper(int nums[], boolean visit[], List perm, List> res){ 14 | //Base Case 15 | if(perm.size() == nums.length){ 16 | res.add(new ArrayList<>(perm)); 17 | return; 18 | } 19 | 20 | for(int i = 0 ; i < nums.length ; i++){ 21 | //Check if nums[i] is already in the current permutation or not 22 | if(visit[i]) continue; 23 | 24 | //mark nums[i] as visited for the current permutation 25 | visit[i] = true; 26 | perm.add(nums[i]); 27 | 28 | //generate the permutation further 29 | helper(nums, visit, perm, res); 30 | 31 | //backtrack to generate new permutation 32 | visit[i] = false; 33 | perm.remove(perm.size()-1); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Backtracking/PermutationsII.java: -------------------------------------------------------------------------------- 1 | //LeetCode 47. Permutations II 2 | //Question - https://leetcode.com/problems/permutations-ii/ 3 | 4 | class Solution { 5 | public List> permuteUnique(int[] nums) { 6 | List> res = new ArrayList<>(); 7 | Arrays.sort(nums); 8 | boolean visit[] = new boolean[nums.length]; 9 | 10 | helper(nums, visit, new ArrayList<>(), res); 11 | return res; 12 | } 13 | 14 | public void helper(int nums[], boolean visit[], List perm, List> res){ 15 | //Base Case 16 | if(perm.size() == nums.length){ 17 | res.add(new ArrayList<>(perm)); 18 | return; 19 | } 20 | 21 | for(int i = 0 ; i < nums.length ; i++){ 22 | //Check if nums[i] is already in the current permutation or not 23 | //The 2nd check is for duplicates 24 | 25 | /* 26 | Generating repeated permutations from duplicates can be avoided by using two 27 | different conditions - 28 | 1. (i > 0 && nums[i] == nums[i-1] && visit[i-1]) continue; 29 | This means include current number if the previous identical number is not 30 | included. After tracing out the state space tree, we can see that this condition 31 | creates the permutation by the last duplicate number, any permutation with an 32 | intermediate identical number would never reach the base case and creates a 33 | waste of space and time. 34 | 35 | 2. (i > 0 && nums[i] == nums[i-1] && !visit[i-1]) continue; 36 | This means that include current number if the previous identical number is 37 | included. After tracing out the state space tree, we can see that this condition 38 | creates the permutation by the first duplicate number, any permutation with an 39 | intermediate identical number is stopped from going deeper into recursion, 40 | saving time and space. 41 | */ 42 | if(visit[i] || (i > 0 && nums[i] == nums[i-1] && !visit[i-1])) continue; 43 | 44 | //mark nums[i] as visited for the current permutation 45 | visit[i] = true; 46 | perm.add(nums[i]); 47 | 48 | //generate the permutation further 49 | helper(nums, visit, perm, res); 50 | 51 | //backtrack to generate new permutation 52 | visit[i] = false; 53 | perm.remove(perm.size()-1); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Backtracking/Subsets.java: -------------------------------------------------------------------------------- 1 | //LeetCode 78. Subsets 2 | //Question - https://leetcode.com/problems/subsets/ 3 | 4 | class Solution { 5 | public List> subsets(int[] nums) { 6 | List> res = new ArrayList<>(); 7 | helper(nums, 0, new ArrayList<>(), res); 8 | 9 | return res; 10 | } 11 | 12 | public void helper(int nums[], int index, List subset, List> res){ 13 | res.add(new ArrayList<>(subset)); 14 | 15 | /* 16 | For each element we have two choices - 17 | 1. Include element in current subset 18 | 2. Exclude element from current subset 19 | 20 | We start from index 0 and it considers all elements in the array ==> this leads to the 21 | deepest branch of the state space tree. 22 | 23 | Each level in the state space tree will signify a subset of different length. 24 | 25 | Input ==> [1,2,3] 26 | Output ==> [[],[1],[1,2],[1,2,3],[1,3],[2],[2,3],[3]] 27 | 28 | State space tree ==> 29 | level 0 [] 30 | level 1 [1] [2] [3] 31 | level 2 [1,2] [1,3] [2,3] 32 | level 3 [1,2,3] 33 | */ 34 | 35 | for(int i = index ; i < nums.length ; i++){ 36 | //Choice 1. Include the elment 37 | subset.add(nums[i]); 38 | helper(nums, i + 1, subset, res); 39 | //Choice 2. Exclude the element ==> Basically Backtrack after choosing the element 40 | subset.remove(subset.size()-1); 41 | } 42 | 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Backtracking/SubsetsII.java: -------------------------------------------------------------------------------- 1 | //LeetCode 90. Subsets II 2 | //Question - https://leetcode.com/problems/subsets-ii/ 3 | 4 | class Solution { 5 | public List> subsetsWithDup(int[] nums) { 6 | List> res = new ArrayList<>(); 7 | 8 | //By sorting the array duplicates would come together consecutively 9 | Arrays.sort(nums); 10 | 11 | helper(nums, 0, new ArrayList<>(), res); 12 | return res; 13 | } 14 | 15 | public void helper(int nums[], int index, List subset, List> res){ 16 | res.add(new ArrayList<>(subset)); 17 | 18 | for(int i = index ; i < nums.length ; i++){ 19 | //Always include the first distinct number and ignore the following duplicates 20 | if(i > index && nums[i] == nums[i-1]) continue; 21 | 22 | subset.add(nums[i]); 23 | helper(nums, i+1, subset, res); 24 | subset.remove(subset.size()-1); 25 | 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Backtracking/WordSearch.java: -------------------------------------------------------------------------------- 1 | //LeetCode 79. Word Search 2 | //Question - https://leetcode.com/problems/word-search/ 3 | 4 | class Solution { 5 | public boolean exist(char[][] board, String word) { 6 | 7 | for(int i = 0 ; i < board.length ; i++){ 8 | for(int j = 0 ; j < board[0].length ; j++){ 9 | if(helper(board, i, j, word, 0)) return true; 10 | } 11 | } 12 | return false; 13 | } 14 | 15 | public boolean helper(char[][] b, int x, int y, String s, int end){ 16 | //Base Cases 17 | if(end == s.length()) return true; 18 | 19 | if(x < 0 || x >= b.length || y < 0 || y >= b[0].length) return false; 20 | if(b[x][y] != s.charAt(end)) return false; 21 | 22 | //Mark as visited 23 | b[x][y] = '#'; 24 | 25 | //go deeper into recursion 26 | boolean res = helper(b, x+1, y, s, end+1) || 27 | helper(b, x-1, y, s, end+1) || 28 | helper(b, x, y+1, s, end+1) || 29 | helper(b, x, y-1, s, end+1); 30 | //backtarck 31 | b[x][y] = s.charAt(end); 32 | 33 | return res; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /BinarySearch/Count_Negative_Numbers_in_a_Sorted_Matrix.java: -------------------------------------------------------------------------------- 1 | //Leetcode 1351. Count Negative Numbers in a Sorted Matrix 2 | //Question - https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix/ 3 | 4 | /*Given a m * n matrix grid which is sorted in non-increasing order both row-wise and column-wise. 5 | Return the number of negative numbers in grid. 6 | 7 | Example 1: 8 | 9 | Input: grid = [[4,3,2,-1],[3,2,1,-1],[1,1,-1,-2],[-1,-1,-2,-3]] 10 | Output: 8 11 | Explanation: There are 8 negatives number in the matrix. 12 | 13 | Example 2: 14 | 15 | Input: grid = [[3,2],[1,0]] 16 | Output: 0 17 | 18 | Example 3: 19 | 20 | Input: grid = [[1,-1],[-1,-1]] 21 | Output: 3 22 | 23 | Example 4: 24 | 25 | Input: grid = [[-1]] 26 | Output: 1 27 | */ 28 | 29 | 30 | class Solution { 31 | public int countNegatives(int[][] grid) { 32 | int m = grid.length; 33 | int n = grid[0].length; 34 | int low = 0; 35 | int high = n-1; 36 | int mid = -1; 37 | int result = -1; 38 | int target = 0; 39 | int ans = 0; 40 | 41 | 42 | for(int i=0;i= target){ //push algo to right ==> find first negative 49 | low = mid + 1; 50 | } 51 | else{ 52 | result = mid; //store current result 53 | high = mid - 1; //push the upper bound to find the first negative 54 | } 55 | } 56 | 57 | //if all the numbers are positives or zeros result will be -1 58 | if(result!=-1){ 59 | ans+=(n-result); 60 | } 61 | } 62 | 63 | return ans; 64 | } 65 | } 66 | 67 | 68 | /* Most Voted Solution - 69 | This solution uses the fact that the negative regions of the matrix will form a "staircase" shape, e.g.: 70 | 71 | ++++++ 72 | ++++-- 73 | ++++-- 74 | +++--- 75 | +----- 76 | +----- 77 | 78 | What this solution then does is to "trace" the outline of the staircase. 79 | Start from bottom-left corner of the matrix, count in the negative numbers in each row. 80 | */ 81 | 82 | public int countNegatives(int[][] grid) { 83 | int m = grid.length, n = grid[0].length, r = m - 1, c = 0, cnt = 0; 84 | while (r >= 0 && c < n) { 85 | if (grid[r][c] < 0) { 86 | --r; 87 | cnt += n - c; // there are n - c negative numbers in current row. 88 | }else { 89 | ++c; 90 | } 91 | } 92 | return cnt; 93 | } 94 | 95 | /*Simlarly, you can also start from top-right corner, whichever you feel comfortable with, count in the negative numers in each column.*/ 96 | 97 | public int countNegatives(int[][] grid) { 98 | int m = grid.length, n = grid[0].length, r = 0, c = n - 1, cnt = 0; 99 | while (r < m && c >= 0) { 100 | if (grid[r][c] < 0) { 101 | --c; 102 | cnt += m - r; // there are m - r negative numbers in current column. 103 | }else { 104 | ++r; 105 | } 106 | } 107 | return cnt; 108 | } 109 | -------------------------------------------------------------------------------- /BinarySearch/Find_Peak_Element.java: -------------------------------------------------------------------------------- 1 | //Leetcode 162. Find Peak Element 2 | //Question - https://leetcode.com/problems/find-peak-element/ 3 | 4 | /*A peak element is an element that is greater than its neighbors. 5 | 6 | Given an input array nums, where nums[i] ≠ nums[i+1], find a peak element and return its index. 7 | 8 | The array may contain multiple peaks, in that case return the index to any one of the peaks is fine. 9 | 10 | You may imagine that nums[-1] = nums[n] = -∞. 11 | 12 | Example 1: 13 | 14 | Input: nums = [1,2,3,1] 15 | Output: 2 16 | Explanation: 3 is a peak element and your function should return the index number 2. 17 | 18 | Example 2: 19 | 20 | Input: nums = [1,2,1,3,5,6,4] 21 | Output: 1 or 5 22 | Explanation: Your function can return either index number 1 where the peak element is 2, 23 | or index number 5 where the peak element is 6. 24 | 25 | Note: 26 | 27 | Your solution should be in logarithmic complexity. 28 | */ 29 | 30 | class Solution { 31 | //We can view any given sequence in numsnumsnums array as alternating ascending and descending sequences. 32 | public int findPeakElement(int[] nums) { 33 | if(nums.length==0 || nums==null) return -1; 34 | else if(nums.length==1) return 0; 35 | 36 | 37 | //We start off by finding the middle element, mid from the given nums array. 38 | //If this element happens to be lying in a descending sequence of numbers. 39 | //or a local falling slope(found by comparing nums[i]nums[i]nums[i] to its right neighbour), 40 | //it means that the peak will always lie towards the left of this element. 41 | //Thus, we reduce the search space to the left of midmidmid(including itself) and perform the same process on left subarray. 42 | 43 | //If the middle element, mid lies in an ascending sequence of numbers 44 | //or a rising slope(found by comparing nums[i]nums[i]nums[i] to its right neighbour), 45 | //it obviously implies that the peak lies towards the right of this element. 46 | //Thus, we reduce the search space to the right of midmidmid and perform the same process on the right subarray. 47 | 48 | //In this way, we keep on reducing the search space till we eventually reach a state where only one element is remaining in the search space. 49 | //This single element is the peak element. 50 | 51 | int low = 0; 52 | int high = nums.length-1; 53 | while(low < high){ 54 | int mid = low + (high-low)/2; 55 | if(nums[mid] <= nums[mid+1]){ 56 | low = mid + 1; 57 | } 58 | else high = mid; 59 | } 60 | 61 | return low; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /BinarySearch/First_Bad_Version.java: -------------------------------------------------------------------------------- 1 | //Leetcode 278. First Bad Version 2 | //Question - https://leetcode.com/problems/first-bad-version/ 3 | 4 | /*You are a product manager and currently leading a team to develop a new product. Unfortunately, the latest version of your product fails the quality check. Since each version is developed based on the previous version, all the versions after a bad version are also bad. 5 | 6 | Suppose you have n versions [1, 2, ..., n] and you want to find out the first bad one, which causes all the following ones to be bad. 7 | 8 | You are given an API bool isBadVersion(version) which will return whether version is bad. Implement a function to find the first bad version. You should minimize the number of calls to the API. 9 | 10 | Example: 11 | 12 | Given n = 5, and version = 4 is the first bad version. 13 | 14 | call isBadVersion(3) -> false 15 | call isBadVersion(5) -> true 16 | call isBadVersion(4) -> true 17 | 18 | Then 4 is the first bad version.*/ 19 | 20 | /* The isBadVersion API is defined in the parent class VersionControl. 21 | boolean isBadVersion(int version); */ 22 | 23 | public class Solution extends VersionControl { 24 | public int firstBadVersion(int n) { 25 | int low = 1; 26 | int high = n; 27 | 28 | while(low < high){ 29 | int mid = low + (high-low)/2; 30 | boolean isBad = isBadVersion(mid); 31 | 32 | if(isBad){ 33 | high = mid; 34 | } 35 | else low = mid + 1; 36 | } 37 | 38 | return low; 39 | } 40 | } 41 | 42 | //OR 43 | 44 | public class Solution extends VersionControl { 45 | public int firstBadVersion(int n) { 46 | int low = 1; 47 | int high = n; 48 | int result = -1; 49 | 50 | while(low<=high){ 51 | int mid = low + (high-low)/2; 52 | boolean isBad = isBadVersion(mid); 53 | 54 | if(isBad){ 55 | result = mid; 56 | high = mid-1; 57 | } 58 | else low = mid + 1; 59 | } 60 | 61 | return result; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /BinarySearch/Guess_Number_Higher_or_Lower.java: -------------------------------------------------------------------------------- 1 | //Leetcode 374. Guess Number Higher or Lower 2 | //Question - https://leetcode.com/problems/guess-number-higher-or-lower/ 3 | 4 | /*We are playing the Guess Game. The game is as follows: 5 | 6 | I pick a number from 1 to n. You have to guess which number I picked. 7 | 8 | Every time you guess wrong, I'll tell you whether the number is higher or lower. 9 | 10 | You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0): 11 | 12 | -1 : My number is lower 13 | 1 : My number is higher 14 | 0 : Congrats! You got it! 15 | 16 | Example : 17 | 18 | Input: n = 10, pick = 6 19 | Output: 6 20 | 21 | */ 22 | 23 | /* The guess API is defined in the parent class GuessGame. 24 | @param num, your guess 25 | @return -1 if my number is lower, 1 if my number is higher, otherwise return 0 26 | int guess(int num); */ 27 | 28 | public class Solution extends GuessGame { 29 | public int guessNumber(int n) { 30 | int low = 1; 31 | int high = n; 32 | 33 | while(low<=high){ 34 | 35 | int mid = low + (high-low)/2; 36 | int res = guess(mid); 37 | 38 | if(res==0) return mid; 39 | else if(res==-1) high = mid - 1; 40 | else low = mid + 1; 41 | } 42 | return -1; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /BinarySearch/Peak_Index_in_a_Mountain_Array.java: -------------------------------------------------------------------------------- 1 | //Leetcode 852. Peak Index in a Mountain Array 2 | //Question - https://leetcode.com/problems/peak-index-in-a-mountain-array/ 3 | 4 | /*Let's call an array A a mountain if the following properties hold: 5 | 6 | A.length >= 3 7 | There exists some 0 < i < A.length - 1 such that A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1] 8 | 9 | Given an array that is definitely a mountain, return any i such that A[0] < A[1] < ... A[i-1] < A[i] > A[i+1] > ... > A[A.length - 1]. 10 | 11 | Example 1: 12 | 13 | Input: [0,1,0] 14 | Output: 1 15 | 16 | Example 2: 17 | 18 | Input: [0,2,1,0] 19 | Output: 1 20 | 21 | Note: 22 | 23 | 3 <= A.length <= 10000 24 | 0 <= A[i] <= 10^6 25 | A is a mountain, as defined above. 26 | 27 | */ 28 | 29 | class Solution { 30 | public int peakIndexInMountainArray(int[] A) { 31 | int low = 0; 32 | int high = A.length-1; 33 | int ans = -1; 34 | 35 | while(low <= high){ 36 | int mid = low + (high-low)/2; 37 | if(A[mid] < A[mid+1]) low = mid + 1; 38 | else{ 39 | ans = mid; 40 | high = mid-1; 41 | } 42 | } 43 | return ans; 44 | } 45 | 46 | } 47 | 48 | //OR 49 | 50 | class Solution { 51 | public int peakIndexInMountainArray(int[] A) { 52 | int low = 0; 53 | int high = A.length-1; 54 | 55 | while(low < high){ 56 | int mid = low + (high-low)/2; 57 | if(A[mid] < A[mid+1]) low = mid + 1; 58 | else{ 59 | high = mid; 60 | } 61 | } 62 | return low; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /BinarySearch/Search_Insert_Position.java: -------------------------------------------------------------------------------- 1 | //Leetcode 35. Search Insert Position 2 | //Question - https://leetcode.com/problems/search-insert-position/ 3 | 4 | /*Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order. 5 | 6 | You may assume no duplicates in the array. 7 | Example 1: 8 | 9 | Input: [1,3,5,6], 5 10 | Output: 2 11 | 12 | Example 2: 13 | 14 | Input: [1,3,5,6], 2 15 | Output: 1 16 | 17 | Example 3: 18 | 19 | Input: [1,3,5,6], 7 20 | Output: 4 21 | 22 | Example 4: 23 | 24 | Input: [1,3,5,6], 0 25 | Output: 0 26 | */ 27 | 28 | class Solution { 29 | public int searchInsert(int[] nums, int target) { 30 | int index = -1; 31 | int low = 0; int high = nums.length-1; 32 | int mid = -1; 33 | int result = -1; 34 | 35 | while(low<=high){ 36 | mid = low + (high-low)/2; 37 | 38 | if(nums[mid]==target) return mid; //if target is present 39 | 40 | else if(nums[mid]>target){ 41 | result = mid; //store the latest mid ==> this could be the first occurrence of least element greater than target 42 | high = mid - 1; //push algorithm to left in hopes to find first occurrence of least element greater than target OR to find the target itself 43 | } 44 | else low = mid+1; 45 | } 46 | 47 | //if the control is here the target value must not be in nums 48 | if(result==-1) return nums.length; //No element in nums was greater than target ==> the target is the greatest ==> needs to be added at the end 49 | else return result;//correct position for target found 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /BinarySearch/Search_in_Rotated_Sorted_Array.java: -------------------------------------------------------------------------------- 1 | //Leetcode 33. Search in Rotated Sorted Array 2 | //Question - https://leetcode.com/problems/search-in-rotated-sorted-array/ 3 | 4 | /*Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand. 5 | 6 | (i.e., [0,1,2,4,5,6,7] might become [4,5,6,7,0,1,2]). 7 | 8 | You are given a target value to search. If found in the array return its index, otherwise return -1. 9 | 10 | You may assume no duplicate exists in the array. 11 | 12 | Your algorithm's runtime complexity must be in the order of O(log n). 13 | 14 | Example 1: 15 | 16 | Input: nums = [4,5,6,7,0,1,2], target = 0 17 | Output: 4 18 | 19 | Example 2: 20 | 21 | Input: nums = [4,5,6,7,0,1,2], target = 3 22 | Output: -1 23 | 24 | */ 25 | 26 | class Solution { 27 | public int search(int[] nums, int target) { 28 | int len = nums.length; 29 | int low = 0; 30 | int high = len-1; 31 | 32 | //finding index of pivot 33 | while(low < high){ 34 | int mid = low + (high-low)/2; 35 | if(nums[mid] > nums[high]) low = mid + 1; 36 | else high = mid; 37 | } 38 | 39 | int pivotIndex = low; 40 | low = 0; 41 | high = len-1; 42 | while(low <= high){ 43 | //calculating mid according to orignal array sorted in ascending order 44 | int mid = low + (high-low)/2; 45 | 46 | //calculating mid in accordance to rotated array 47 | //each element is displaced by "pivot" ==> add pivot ==> modulo becuase the rotation is circular 48 | int midOfRotatedArray = (mid + pivotIndex) % len; 49 | 50 | if(nums[midOfRotatedArray]==target) return midOfRotatedArray; 51 | else if(nums[midOfRotatedArray] < target) low = mid + 1; 52 | else high = mid - 1; 53 | } 54 | return -1; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /BinarySearch/Sqrt(x).java: -------------------------------------------------------------------------------- 1 | //Leetcode 69. Sqrt(x) 2 | //Question - https://leetcode.com/problems/sqrtx/ 3 | //Further Reading - Newton's root-finding algorithm 4 | 5 | /*Implement int sqrt(int x). 6 | 7 | Compute and return the square root of x, where x is guaranteed to be a non-negative integer. 8 | 9 | Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned. 10 | 11 | Example 1: 12 | 13 | Input: 4 14 | Output: 2 15 | 16 | Example 2: 17 | 18 | Input: 8 19 | Output: 2 20 | Explanation: The square root of 8 is 2.82842..., and since 21 | the decimal part is truncated, 2 is returned. 22 | 23 | */ 24 | 25 | class Solution { 26 | public int mySqrt(int x) { 27 | if(x==0) return 0; //corner case 28 | 29 | int low = 1; 30 | int high = x; 31 | //search range is [1,x] 32 | //can be improved further ==> [1, x/2] 33 | //(you need to do math to prove it: x/2 should include the sqrt(x), i.e. (x/2)^2 >= x, then x >= 2. 34 | 35 | int result = -1; 36 | while(low<=high){ 37 | int mid = low + (high-low)/2; 38 | if(mid<=x/mid){ //use this condition and not (mid*mid<=x) because it might cause integer overflow 39 | result = mid; 40 | low = mid + 1; 41 | } 42 | else high = mid - 1; 43 | } 44 | return result; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /DynamicProgramming/#BinaryStringsWithoutConsecutive1s.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/count-number-binary-strings-without-consecutive-1s/ 3 | 4 | Given a positive integer N, count all possible distinct binary strings of length N such that there are no consecutive 1’s. 5 | 6 | Examples: 7 | 8 | Input: N = 2 9 | Output: 3 10 | // The 3 strings are 00, 01, 10 11 | 12 | Input: N = 3 13 | Output: 5 14 | // The 5 strings are 000, 001, 010, 100, 101 15 | 16 | Let, 17 | 1. a[i] = #binary strings of length i which do not contain any two consecutive 1’s and which END IN 0. 18 | 2. b[i] = #binary strings of length i which do not contain any two consecutive 1’s and which END IN 1. 19 | 20 | We can append either 0 or 1 to a string ending in 0, but we can only append 0 to a string ending in 1. 21 | This yields the recurrence relation: 22 | a[i] = a[i - 1] + b[i - 1] 23 | b[i] = a[i - 1] 24 | 25 | The base cases of above recurrence are a[1] = b[1] = 1. The total number of strings of length i is just a[i] + b[i]. 26 | */ 27 | 28 | public int countStrings(int n){ 29 | int endsIn0[] = new int[n]; 30 | int endsIn1[] = new int[n]; 31 | 32 | endsIn1[0] = 1; 33 | endsIn0[0] = 1; 34 | 35 | for(int i=1 ; i < n ; i++){ 36 | endsIn0[i] = endsIn0[i-1] + endsIn1[i-1]; 37 | endsIn1[i] = endsIn0[i-1]; 38 | } 39 | 40 | return (endsIn0[n] + endsIn1[n]); 41 | } 42 | 43 | /* 44 | Time Complexity and Space Complexity - O(n) 45 | */ 46 | 47 | -------------------------------------------------------------------------------- /DynamicProgramming/#PathsInMatrixWithGivenCost.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/counting-paths-on-grid-to-reach-destination-cell/ 3 | https://www.geeksforgeeks.org/number-of-paths-with-exactly-k-coins/ 4 | 5 | 6 | pathCount(m, n, k): Number of paths to reach mat[m][n] from mat[0][0] 7 | when cost = k 8 | 9 | If (m == 0 and n == 0) 10 | return 1 if mat[0][0] == k else return 0 11 | Else: 12 | pathCount(m, n, k) = pathCount(m-1, n, k - mat[m][n]) + 13 | pathCount(m, n-1, k - mat[m][n]) 14 | 15 | Normal Recursion 16 | */ 17 | 18 | public int pathCount(int A[][], int row, int col, int cost){ 19 | //Base Case 20 | if(cost<0) return 0; 21 | //Base Case --> Valid path 22 | else if(row==0 && col==0 && cost == A[0][0]) return 1; 23 | //Base Case 24 | else if(row==0 && col==0 && cost != A[0][0]) return 0; 25 | 26 | //First row --> Only one move --> Go left 27 | else if(row == 0) return pathCount(A, row, col-1, cost-A[row][col]); 28 | 29 | //First col --> Only one move --> Go up 30 | else if(col == 0) return pathCount(A, row-1, col, cost-A[row][col]); 31 | 32 | //Cosider both --> up and left 33 | else return pathCount(A, row-1, col, cost-A[row][col]) + pathCount(A, row, col-1, cost-A[row][col]); 34 | } 35 | 36 | //Memoized Recursion - using a hashmap 37 | 38 | public int pathCount(int A[][], int row, int count, int cost, HashMap map){ 39 | if(cost<0) return 0; 40 | 41 | else if(row==0 && col==0 && cost == A[0][0]) return 1; 42 | 43 | else if(row==0 && col==0 && cost != A[0][0]) return 0; 44 | 45 | String key = row+"|"+col+"|"+cost; 46 | 47 | if(!map.containsKey(key)){ 48 | else if(row == 0) map.put(key, pathCount(A, row, col-1, cost-A[row][col])); 49 | 50 | else if(col == 0) map.put(key, pathCount(A, row-1, col, cost-A[row][col])); 51 | 52 | else map.put(key, pathCount(A, row-1, col, cost-A[row][col]) + pathCount(A, row, col-1, cost-A[row][col])); 53 | } 54 | return map.get(key); 55 | } 56 | 57 | //Memoized recursion - using an 3d array 58 | 59 | public int pathCount(int A[][], int row, int col, int cost, int dp[][]){ 60 | if(cost<0) return 0; 61 | 62 | else if(row==0 && col==0 && cost == A[0][0]) return 1; 63 | 64 | else if(row==0 && col==0 && cost != A[0][0]) return 0; 65 | 66 | else if(dp[row][col][cost] != -1) return dp[row][col][cost]; 67 | else{ 68 | dp[row][col][cost] = pathCount(A, row-1, col, cost-A[row][col]) + pathCount(A, row, col-1, cost-A[row][col]); 69 | 70 | return dp[row][col][cost]; 71 | } 72 | } 73 | 74 | //Time Complexity of DP solution - O(n*m*cost) 75 | //This is Psedo-Polynomial Time 76 | -------------------------------------------------------------------------------- /DynamicProgramming/#SolutionsOfLinearEqtn.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/total-possible-solutions-linear-equation-k-variables/ 3 | 4 | Problem is similar to the problem - number of ways to change coin. 5 | We either include the current coefficient or exlcude it. 6 | 7 | Recurrence - 8 | count(coeff, k, rhs) = count(coeff, k, rhs-coeff[k]) + count(coeff, k-1, rhs) 9 | where, count(coeff, k, rhs-coeff[k]) --> including coeff[k] 10 | count(coeff, k-1, rhs) --> excluding coeff[k] 11 | */ 12 | 13 | //Recursion 14 | 15 | public int count(int coeff[], int index, int rhs){ 16 | //Base Case: we have considered valid coeff and their summation equals rhs 17 | if(rhs == 0) return 1; 18 | 19 | //Base Case: we have considered invalid coeff and their summation does not equals rhs 20 | else if(rhs<0 || index< 0) return 0; 21 | 22 | //Include the current coeff 23 | int includeIndex = count(coeff, index, rhs-coeff[index]); 24 | 25 | //Exclude the current coeff 26 | int excludeIndex = count(coeff, index-1, rhs); 27 | 28 | return include + exclude; 29 | } 30 | 31 | 32 | //Memoized Recursion 33 | public int count(int coeff[], int index, int rhs, HashMap map){ 34 | 35 | //Base Case: we have considered valid coeff and their summation equals rhs 36 | if(rhs == 0) return 1; 37 | 38 | //Base Case: we have considered invalid coeff and their summation does not equals rhs 39 | else if(rhs<0 || index< 0) return 0; 40 | 41 | String key = index + "|" + rhs; 42 | 43 | if(!map.containsKey(key)){ 44 | //Include the current coeff 45 | int includeIndex = count(coeff, index, rhs-coeff[index]); 46 | 47 | //Exclude the current coeff 48 | int excludeIndex = count(coeff, index-1, rhs); 49 | 50 | map.put(key, include + exclude); 51 | } 52 | 53 | return map.get(key); 54 | 55 | } 56 | 57 | //Bottom up DP 58 | public int count(int coeff[], int rhs){ 59 | int numOfCoeff = coeff.length; 60 | 61 | //dp[i] indicates the number of ways to form a sum, sum = i 62 | int dp[] = new int[numOfCoeff+1]; 63 | dp[0] = 1; 64 | 65 | /* 66 | we consider all coefficients in the range [0...i] when computing dp[] 67 | for first interation i = 0 --> only first coeff is considered 68 | for second iteration i = 1 --> first two coeficients are considered [0,1] 69 | for last interation i = numOfCoeff --> all coefficients are considered 70 | 71 | We basically answer the question - 72 | #ways to sum up to j when we conisder only the first coefficient? 73 | #ways to sum up to j when we conisder the first two coefficients? 74 | ..... 75 | #ways to sum up to RHS when we consider all coefficients 76 | */ 77 | for(int i=0 ; i < numOfCoeff ; i++){ 78 | for(int j=coeff[i] ; j <= rhs ; j++){ 79 | //since we are including coeff[i] in sum = j, we must add #ways to get a sum = (j-coeff[i]) 80 | dp[j] += dp[ j - coeff[i] ]; 81 | } 82 | } 83 | 84 | return dp[rhs]; 85 | } 86 | 87 | 88 | /* 89 | Time Complexity - O(numberOfCoefficients * RHS) 90 | Pseudo Polynomial 91 | */ 92 | 93 | -------------------------------------------------------------------------------- /DynamicProgramming/0-1KnapsackProblem.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/0-1-knapsack-problem/ 3 | https://www.geeksforgeeks.org/0-1-knapsack-problem-dp-10/ 4 | 5 | To Do - Print the selected items to be put in the kanpsack 6 | */ 7 | 8 | /* 9 | In the 0/1 Knapsack Problem we must include an item entirely or exclude the item with an objective 10 | of maximizing profit/value constrainted by the size of the knapsack. 11 | 12 | If the problem is not 0/1 knapsack and we are allowed to split items, we can take a greedy approach 13 | we can chose items by sorting items according to profit per unit weight. 14 | In doing so, only the last element or a single element will have to be split. 15 | */ 16 | 17 | /*RECURSION 18 | For each item we have 2 choices - 19 | 1. Include the item and recur for the remaining item. Here the capacity of the knapsack is reduced. 20 | 2. Exclude the item and recur for the remaining item. Capacity of knapsack remains the same. 21 | 22 | */ 23 | 24 | public int knapsack(int W, int item, int wt[], int val[]){ 25 | //BASE CASE: we have exhausted all items or we have utilized the entire capacity of knapsack 26 | if(n==0 || W==0) return 0; 27 | 28 | //If the weight of current item exceeds the capacity of knapsack it can not be included - EXCLUDE ITEM 29 | else if(wt[n-1] > W) return knapsack(W, item-1, wt, val); 30 | 31 | //Try both - INCLUDE AND EXCLUDE - chose the best 32 | else return Math.max(knapsack(W, item-1, wt, val), val[item-1] + knapsack(W-wt[item-1], item-1, wt, val)) 33 | } 34 | 35 | 36 | /* 37 | Time Complexity - O(2^n) 38 | For each item we are exploring the two choices(We include and exclude each item) to find the best. 39 | */ 40 | 41 | /* 42 | DYNAMIC PROGRAMMING - BOTTOM UP APPROACH 43 | */ 44 | 45 | public int knapsack(int W, int items, int wt[], int val[]){ 46 | int k[][] = new int[items+1][W+1]; 47 | 48 | for(int item=0 ; item <= items ; item++){ 49 | for(int w=0 ;w <= W ; w++){ 50 | //Base Case: when items = 0 or capacity of knapsack = 0 51 | if(item==0 || w==0) k[item][w] = 0; 52 | 53 | //if weight of current item exceeds the knapsack capacity we EXCLUDE current item 54 | //Simply put the value which was calculated with respect to previous item and same knapsack capacity 55 | else if(wt[item-1] > w) k[item][w] = k[item-1][w]; 56 | 57 | //If the weight of item does not exceed knapsack's capacity - we explore 2 choices 58 | //1. INCLUDE current item - we find the cell that represents a state which has been calculated with respect to the 59 | //previous item and knapsack's capacity reduced by current item's weight ie, k[item-1][w-wt[item-1]] 60 | //2. EXCLUDE current item - value same as the one which was calculated 61 | //with respect to previous item and same knapsack capacity 62 | else k[item][w] = Math.max( k[item-1][w], val[item-1] + k[item-1][w-wt[item-1]]); 63 | } 64 | } 65 | 66 | return k[items][W]; 67 | } 68 | 69 | /* 70 | Time and Space Complexity - O(items * knapsackCapacity) 71 | */ 72 | 73 | //RECURSION USING MEMOIZATION 74 | 75 | public int knapsack(int W, int item, int wt[], int val[], HashMap map){ 76 | if(W==0 || item==0) return 0; 77 | 78 | String key = item + "|" + W; 79 | int include = 0; 80 | int exclude = 0; 81 | if(!map.containsKey(key)){ 82 | if(wt[item] < W) include = v[n] + knapsack(W-w[n],item-1,wt,val,map); 83 | exclude = knapsack(W,item-1,wt,val,map); 84 | 85 | map.put(key, Math.max(include,exclude)); 86 | } 87 | return map.get(key); 88 | } 89 | 90 | //Time Complexity - O(n*W) 91 | //where n - number of items and W - capacity of knapsack 92 | 93 | 94 | -------------------------------------------------------------------------------- /DynamicProgramming/BoxStackingProblem.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/box-stacking-problem-dp-22/ 3 | 4 | Question is on the same lines as the Longest Increasing Subsequence 5 | */ 6 | 7 | class Box implements Comparable{ 8 | 9 | // h --> height, w --> width, d --> depth 10 | int h, w, d, area; 11 | 12 | // for simplicity of solution, 13 | // always keep w <= d 14 | 15 | /*Constructor to initialise object*/ 16 | public Box(int h, int w, int d) { 17 | this.h = h; 18 | this.w = w; 19 | this.d = d; 20 | } 21 | 22 | /*To sort the box array on the basis 23 | of area in decreasing order of area */ 24 | public int compareTo(Box o) { 25 | return o.area-this.area; 26 | } 27 | } 28 | 29 | //DYNAMIC PROGRAMMING - BOTTOM UP APPROACH 30 | class BoxStack{ 31 | public int maxHeight(Box b[]){ 32 | int n = b.length; 33 | Box allBoxes[] = new Box[n*3]; 34 | 35 | //creating all rotations of a box 36 | for(int i=0 ; i < n ; i++){ 37 | Box box = b[i]; 38 | allBoxes[i*3] = new Box(box.h, Math.max(box.d, box.w), Math.min(box.d, box.w)); 39 | allBoxes[i*3 + 1] = new Box(box.d, Math.max(box.h, box.w), Math.min(box.h, box.w)); 40 | allBoxes[i*3 + 2] = new Box(box.w, Math.max(box.d, box.h), Math.min(box.d, box.h)); 41 | } 42 | 43 | //calculating area of the boxes - we need this because each box must have smaller length and breadth than the box below it 44 | //this helps us to explore only valid subproblems - explore the boxes having greater dimensions than the current one 45 | for(int i=0 ; i < n*3 ; i++) allBoxes[i].area = allBoxes[i].d * allBoxes[i].w; 46 | 47 | //sorting in descending order according to the area 48 | Arrays.sort(allBoxes); 49 | 50 | //msh[i] indicates the maximum possible height of a stack when box i is at the top 51 | int msh[] = new int[n*3]; 52 | 53 | //storing the current height of each of the box 54 | for(int i=0 ; i < n*3 ; i++) msh[i] = allBoxes[i].h; 55 | 56 | //for each of the box, we compute the maximum stack height when it is at the top 57 | for(int i=0 ; i < n*3 ; i++){ 58 | 59 | Box topBox = allBoxes[i]; 60 | 61 | //initializing maximum stack height of the subproblem 62 | int maxH = 0; 63 | 64 | //SUBPROBLEMS - explore all boxes greater in dimension than the current one to find the one giving the maximum height 65 | for(int j=0 ; j < i ; j++){ 66 | 67 | Box bottomBox = allBoxes[j]; 68 | 69 | //Constraints - greater dimensions than the current box 70 | if(topBox.w < bottomBox.w && topBox.d < bottomBox.d){ 71 | //Out of all the subproblems consider the one giving max height 72 | //This box comes below the current box 73 | maxH = Math.max(maxH, msh[j]); 74 | } 75 | } 76 | 77 | //Store the result - add the height of the box to the calculated max height from the subproblems 78 | msh[i] = maxH + topBox.h; 79 | } 80 | 81 | int maxstackHeight = -1; 82 | for(int i=0 ; i < n*3 ; i++){ 83 | if(maxstackHeight < msh[i]) maxstackHeight = msh[i]; 84 | } 85 | 86 | return maxstackHeight; 87 | 88 | } 89 | } 90 | 91 | 92 | /* 93 | Time Complexity - O(n^2) 94 | Space Complexity - O(n) 95 | */ 96 | 97 | 98 | -------------------------------------------------------------------------------- /DynamicProgramming/CoinChangeWays/CoinChangeNumberOfWays.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/coin-change-dp-7/ 3 | 4 | Given a value N, if we want to make change for N cents, and we have infinite supply of each of S = { S1, S2, .. , Sm} valued coins, how many ways can we make the change? The order of coins doesn’t matter. 5 | 6 | For N = 4 and S = {1,2,3}, there are four solutions: {1,1,1,1},{1,1,2},{2,2},{1,3}. So output should be 4. 7 | For N = 10 and S = {2, 5, 3, 6}, there are five solutions: {2,2,2,2,2}, {2,2,3,3}, {2,2,6}, {2,3,5} and {5,5}. So the output should be 5. 8 | 9 | OPTIMAL SUBSTRUCTURE 10 | Here S[] = array of coin denomination 11 | m = number of coins (S.length) 12 | n = Given sum(coin) whose change is to be calculated 13 | 14 | To count the total number of solutions, we can divide all set solutions into two sets. 15 | 1) Solutions that do not contain mth coin (or Sm). ==> count(S[], m-1, n) ==> EXCLUDE CURRENT COIN 16 | 2) Solutions that contain at least one Sm. ==> count(S[], m, n-S[m]) ==> INCLUDE CURRENT COIN 17 | count(S[], m, n) = count(S[], m-1, n) + count(S[], m, n-Sm) 18 | 19 | */ 20 | 21 | //RECURSIVE SOLUTION - COUNTS DISTINCT SOLUTION SETS 22 | 23 | public int coinChangeWays(int coins[], int index, int coinVal){ 24 | 25 | if(coinVal == 0) return 1; 26 | 27 | else if(coinVal < 0) return 0; 28 | 29 | else if(coinVal > 0 && index <= 0) 30 | 31 | else return coinChangeWays(coins, index-1, coinVal) + coinChangeWays(coins, index, coinVal-coins[index-1]); 32 | } 33 | 34 | //DYNAMIC PROGRAMMING - BOTTOM UP APPROACH 35 | 36 | public int coinChangeWays(int coins[], int numOfCoins, int coinVal){ 37 | 38 | //ways[i][j] indicates the number of ways in which a value=j can be changed(formed) by considering coins from [1...i] 39 | int ways[][] = new int[numOfCoins+1][coinVal+1]; 40 | 41 | for(int i=0 ; i <= numOfCoins ; i++) ways[i][0] = 1; 42 | 43 | for(int i=1 ; i <= numOfCoins ; i++){ 44 | for(int j=1 ; j <= coinVal ; j++){ 45 | 46 | //include current coin if [currentVal(j)-currentCoinValue(coins[i-1]) >= 0] 47 | //Basically check, if it is possible to include coin or not 48 | if(j >= coins[i-1]){ 49 | //include coin + exclude coin 50 | ways[i][j] = ways[i-1][j] + ways[i][j - coins[i-1]]; 51 | } 52 | //exclude current coin - value(j) remains same 53 | else ways[i][j] = ways[i-1][j]; 54 | } 55 | } 56 | 57 | return ways[numOfCoins][coinVal]; 58 | } 59 | 60 | /* 61 | Time Complexity - O(numOfCoins * coinVal) 62 | Space Complexity - O(numOfCoins * coinVal) 63 | */ 64 | 65 | //DYNAMIC PROGRAMMING - SPACE OPTIMIZED BOTTOM APPROACH 66 | public int coinChangeWays(int coins[], int coinVal){ 67 | int ways[] = new int[coinVal+1]; 68 | ways[0] = 1; 69 | 70 | for(int coinIndex=0 ; coinIndex < coins.length ; coinIndex++){ 71 | 72 | //currval starts from coins[coinIndex] because for values smaller than coins[coinIndex], 73 | //ways[coinIndex] remains the same ==> excluding coinIndex 74 | 75 | for(int currVal = coins[coinIndex] ; currVal <= coinVal ; currVal++){ 76 | 77 | //including coins[coinIndex] 78 | ways[coinIndex] += ways[currVal - coins[coinIndex]]; 79 | 80 | } 81 | } 82 | 83 | return ways[coinVal]; 84 | } 85 | 86 | /* 87 | Time Complexity - O(numOfCoins * coinVal) 88 | Space Complexity - O(coinVal) 89 | */ 90 | -------------------------------------------------------------------------------- /DynamicProgramming/CountNumberOfWaysToCoverADistance.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/count-number-of-ways-to-cover-a-distance/ 3 | https://www.geeksforgeeks.org/count-number-of-ways-to-cover-a-distance-set-2/ 4 | 5 | Given a distance 'dist', count total number of ways to cover the distance with 1, 2 and 3 steps. 6 | 7 | Examples : 8 | 9 | Input: n = 3 10 | Output: 4 11 | Below are the four ways 12 | 1 step + 1 step + 1 step 13 | 1 step + 2 step 14 | 2 step + 1 step 15 | 3 step 16 | 17 | Input: n = 4 18 | Output: 7 19 | 20 | In the given problem we have 3 choices to cover EACH STEP of a distance X 21 | 1. Take a step of length = 1, remaining dist = X-1 ==> recur on (X-1) 22 | 2. Take a step of length = 2, remaining dist = X-2 ==> recur on (X-2) 23 | 3. Take a step of length = 3, remaining dist = X-3 ==> recur on (X-3) 24 | */ 25 | 26 | public int countPaths(int dist){ 27 | 28 | //if (dist == 0) then the steps taken are valid return 1 to increment the number of valid paths 29 | if(dist == 0) return 1; 30 | 31 | /* 32 | if (dist < 0) then the steps taken are invalid and don't sum to the original distance. This path will not contribute to the 33 | total number of valid paths 34 | */ 35 | else if(dist<0) return 0; 36 | 37 | //explore the 3 choices to find all possible paths 38 | else return (countPaths(dist-1) + countPaths(dist-2) + countPaths(dist-3)); 39 | } 40 | 41 | /* 42 | Time Complexity - O(3^distance) 43 | For each value of distance we explore all the 3 choices to find all possible paths 44 | 1. distance-1 45 | 2. distance-2 46 | 3. distance-3 47 | */ 48 | 49 | /* 50 | DYNAMIC PROGRAMMING - BOTTOM UP APPROACH 51 | The main problem can be divided into subproblems through recursion. 52 | These subproblems are overlapping ==> we can apply dynamic programming 53 | */ 54 | 55 | public int countPaths(int dist){ 56 | //paths[i] indicates the number of possible ways to reach the distance 'i', given we are allowed to take steps 57 | //of length 1, 2 and 3. 58 | int paths[] = new int[dist+1]; 59 | 60 | //Base Cases: becuase each subproblem depends on three smaller subproblems 61 | paths[0] = 1; 62 | paths[1] = 1; 63 | paths[2] = 2; 64 | 65 | for(int d=3 ; d<=dist ; d++){ 66 | //solving subproblem paths[d] with smaller subproblems 67 | paths[d] = paths[d-1] + paths[d-2] + paths[d-3]; 68 | } 69 | 70 | //final ans - total number of paths possible 71 | return paths[dist]; 72 | } 73 | 74 | /* 75 | Time Complexity & Space Complexity - O(distance) 76 | */ 77 | 78 | 79 | /* 80 | DYNAMIC PROGRAMMING - SPACE OPTIMIZED 81 | to calculate the number of steps to cover the distance i, only the last three states are required (i – 1, i – 2, i – 3). 82 | So, keep track of last 3 states only. 83 | */ 84 | 85 | public int countPaths(int dist){ 86 | if(dist==0 || dist==1) return 1; 87 | else if( dist==2 ) return 2; 88 | 89 | int subProb0 = 1; 90 | int subProb1 = 1; 91 | int subProb2 = 2; 92 | int numOfPaths = 0; 93 | 94 | for(int d=3;d<=dist;d++){ 95 | numOfPaths = subProb0 + subProb1 + subProb3; 96 | subProb0 = subProb1; 97 | subProb1 = subProb2; 98 | subProb3 = numOfPaths; 99 | } 100 | 101 | return numOfPaths; 102 | 103 | } 104 | 105 | /* 106 | Time Complexity - O(distance) 107 | Space Complexity - O(1) 108 | */ 109 | -------------------------------------------------------------------------------- /DynamicProgramming/DiceThrow/DiceThrow.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/dice-throw-dp-30/ 3 | 4 | Given n dice each with m faces, numbered from 1 to m, find the number of ways to get sum X. X is the summation of values on each face when all the dice are thrown. 5 | 6 | Let the function to find X from n dice is: Sum(m, n, X) 7 | The function can be represented as: 8 | Sum(m, n, X) = Finding Sum (X - 1) from (n - 1) dice plus 1 from nth dice 9 | + Finding Sum (X - 2) from (n - 1) dice plus 2 from nth dice 10 | + Finding Sum (X - 3) from (n - 1) dice plus 3 from nth dice 11 | ................................................... 12 | ................................................... 13 | ................................................... 14 | + Finding Sum (X - m) from (n - 1) dice plus m from nth dice 15 | 16 | So we can recursively write Sum(m, n, x) as following 17 | Sum(m, n, X) = Sum(m, n - 1, X - 1) + 18 | Sum(m, n - 1, X - 2) + 19 | .................... + 20 | Sum(m, n - 1, X - m) 21 | 22 | Observe Overlapping Problems 23 | Sum(6, 3, 8) = Sum(6, 2, 7) + Sum(6, 2, 6) + Sum(6, 2, 5) + 24 | Sum(6, 2, 4) + Sum(6, 2, 3) + Sum(6, 2, 2) 25 | 26 | To evaluate Sum(6, 3, 8), we need to evaluate Sum(6, 2, 7) which can 27 | recursively written as following: 28 | Sum(6, 2, 7) = Sum(6, 1, 6) + Sum(6, 1, 5) + Sum(6, 1, 4) + 29 | Sum(6, 1, 3) + Sum(6, 1, 2) + Sum(6, 1, 1) 30 | 31 | We also need to evaluate Sum(6, 2, 6) which can recursively written 32 | as following: 33 | Sum(6, 2, 6) = Sum(6, 1, 5) + Sum(6, 1, 4) + Sum(6, 1, 3) + 34 | Sum(6, 1, 2) + Sum(6, 1, 1) 35 | .............................................. 36 | .............................................. 37 | Sum(6, 2, 2) = Sum(6, 1, 1) 38 | */ 39 | 40 | //DYNAMIC PROGRAMMING - BOTTOM UP APPROACH 41 | 42 | public long findWays(int dices, int faces, int sum){ 43 | //HANDLING EXTREMES 44 | /* 45 | Value of sum is too less. 46 | 1. If it is less than the number of dices we return 0. 47 | Minimum value for each dice is 1 ==> minimum sum of all faces of all dices == #dices 48 | 2. If it the sum is equal to the number of dices ==> there is exactly 1 way to get to this sum 49 | */ 50 | if(sum <= dices) return (sum == dices); 51 | 52 | /* 53 | Value of sum is too huge. 54 | max value of all faces of all dices = dices*faces 55 | */ 56 | if(sum >= dices*faces) return (sum == dices*faces); 57 | 58 | //ways[i][j] indicate the number of ways to attain a sum 'j' when we consider dices [1....i] 59 | //0th row and 0th column are not used 60 | long ways[][] = new long[dices+1][sum+1]; 61 | 62 | for(int col=0 ; col <= Math.min(sum,faces) ; col++) ways[1][col] = 1; 63 | 64 | for(int d=2 ; d <= dices ; d++){ 65 | for(int s=1 ; s <= sum ; s++){ 66 | 67 | //to calculate ways[d][s] we explore all faces 68 | for(int f=1 ; f <= Math.min(s-1,faces) ; f++){ 69 | /* 70 | since the current dice 'd' gives a value 'f', we need to find #ways to form a sum of (s-j) without considering 71 | the current dice 'd' 72 | */ 73 | ways[d][s]+=ways[d-1][s-f]; 74 | } 75 | } 76 | } 77 | 78 | return ways[dices][sum]; 79 | } 80 | 81 | /* 82 | Time Complexity - O(dices*sum*faces) 83 | Space Complexity - O(dices*sum) 84 | */ 85 | -------------------------------------------------------------------------------- /DynamicProgramming/EggDroppingPuzzle.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/egg-dropping-puzzle-dp-11/ 3 | 4 | Question: You are given n eggs and specified a number of k floors. Write an algorithm to find the minimum number of drops is required to know the floor from which if the egg is dropped, it will break. 5 | Assumptions - 6 | …..An egg that survives a fall can be used again. 7 | …..A broken egg must be discarded. 8 | …..The effect of a fall is the same for all eggs. 9 | …..If an egg breaks when dropped, then it would break if dropped from a higher floor. 10 | …..If an egg survives a fall then it would survive a shorter fall. 11 | 12 | Optimal Substructure 13 | When we drop an egg from a floor x, there can be two cases (1) The egg breaks (2) The egg doesn’t break. 14 | 15 | 1) If the egg breaks after dropping from xth floor, then we only need to check for floors lower than x with remaining eggs; so the problem reduces to x-1 floors and n-1 eggs 16 | 2) If the egg doesn’t break after dropping from the xth floor, then we only need to check for floors higher than x; so the problem reduces to k-x floors and n eggs. 17 | 18 | Since we need to minimize the number of trials in worst case, we take the maximum of two cases. We consider the max of above two cases for every floor and choose the floor which yields minimum number of trials. 19 | 20 | k ==> Number of floors 21 | n ==> Number of Eggs 22 | eggDrop(n, k) ==> Minimum number of trials needed to find the critical 23 | floor in worst case. 24 | eggDrop(n, k) = 1 + min{max(eggDrop(n - 1, x - 1), eggDrop(n, k - x)): 25 | x in {1, 2, ..., k}} 26 | 27 | */ 28 | 29 | //DYNAMIC PROGRAMMING - BOTTOM UP APPROACH 30 | 31 | public int minEggDrops(int eggs, int floors){ 32 | 33 | if(floors==0 || floors==1 || eggs==1) return floors; 34 | 35 | int drops[][] = new int[eggs+1][floors+1]; 36 | 37 | //when we have only one floor --> #eggs does not matter --> only one drop rqd 38 | for(int i=1 ; i <= eggs ; i++) drops[i][1] = 1; 39 | 40 | //when we have only one egg --> we need to drop it from floor1 then floor2 then floor3...--> In worst case #drops = #floors 41 | for(int j=1 ; j <= floors ; j++) drops[1][j] = j; 42 | 43 | for(int i=2 ; i <= eggs ; i++){ 44 | 45 | for(int j=2 ; j <= floors ; j++){ 46 | 47 | drops[i][j] = Integer.MAX_VALUE; 48 | 49 | //simulating the drop from each floor in the range [1...j] 50 | for(int k=1 ; k <= j ; k++){ 51 | 52 | /* 53 | considering the WORST CASE by choosing the maximum number of drops from each floor 54 | drops[i-1][k-1] --> egg breaks, #floors under consideration reduces by 1 --> all floors below the current floor 55 | drops[i][j-k] --> egg does not break, #floors under consideration --> all floors above the current floor 56 | */ 57 | 58 | int maxDropsForWorstCase = 1 + Math.max(drops[i-1][k-1], drops[i][j-k]); 59 | 60 | /* 61 | After looking through all the floors ie. the maximum number of drops required from each floor, 62 | we chose the floor which gives us the minimum number of drops in the worst case. 63 | ie. We look through the maximum number of drops required for each floor and chose the floor which 64 | results in minimum of all the worst cases 65 | */ 66 | 67 | if(drops[i][j] > maxDropsForWorstCase){ 68 | drops[i][j] = maxDropsForWorstCase; 69 | } 70 | } 71 | } 72 | } 73 | 74 | return drops[eggs][floors]; 75 | } 76 | 77 | /* 78 | Time Complexity - O(eggs * floors^2) 79 | Space Complexity - O(eggs * floors) 80 | */ 81 | -------------------------------------------------------------------------------- /DynamicProgramming/ImplementDiffUtility.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/implement-diff-utility/ 3 | 4 | This is same as the Longest Common Subsequence Problem. 5 | We find the longest common subsequence and for the remaining sequence we print the diff. 6 | 7 | */ 8 | 9 | //Recursion Using lookup table 10 | //X is the initial string, Y is the final string, m = len(X), n = len(Y), dp[][] --> table filled during LCS length computation 11 | 12 | public void printDiff(String X, String Y, int m, int n, int dp[][]){ 13 | //when both characters match we have nothing to do. Print the character and skip it from both the strings. --> m-1 & n-1 14 | if(m>0 && n>0 && (X.charAt(m-1) == Y.charAt(n-1))){ 15 | //Notice the function is called first 16 | printDiff(X, Y, m-1, n-1, dp); 17 | System.out.println(" " + X.charAt(m-1)); 18 | } 19 | 20 | //When characters from Y are not present in X 21 | else if(n > 0 && (m == 0 || (dp[m][n-1] >= dp[m-1][n]))){ 22 | diff(X, Y, m, n-1, dp); 23 | System.out.println("+" + Y.charAt(n-1)); 24 | } 25 | 26 | //when characters from X are not present in Y 27 | else if(m > 0 && (n == 0 || dp[m][n-1] < dp[m-1][n])){ 28 | diff(X, Y, m-1, n, dp); 29 | System.out.println("-" + X.charAt(m-1)); 30 | } 31 | } 32 | 33 | /* 34 | Time and Space Complexity - O(n*m) 35 | */ 36 | -------------------------------------------------------------------------------- /DynamicProgramming/KadaneMaximumSumSubarray.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/maximum-subarray-problem-kadanes-algorithm/ 3 | 4 | We maintain 2 variables - 5 | 1. maxEndingHere - stores the maximum sum of the sub-array ending at the current index 6 | 1.1. Include the current element in the sub-array sum 7 | 1.2. Start a new sub-array from this element ie. sum = current element 8 | 2. maxSoFar - stores the maximum possible sum of all the sub-arrays 9 | */ 10 | 11 | public int kadane(int A[]){ 12 | int n = A.length; 13 | 14 | if(n == 0) return 0; 15 | 16 | int maxEndingHere = A[0]; 17 | int maxSoFar = A[0]; 18 | 19 | for(int i=1 ; i < n ; i++){ 20 | //include current element in the sub-array sum 21 | maxEndingHere+=A[i]; 22 | 23 | //check if starting a new sub-array gives a greater sum than the current sum 24 | maxEndingHere = Math.max(maxEndingHere, A[i]); 25 | 26 | //update the overall max-sum 27 | maxSoFar = Math.max(maxEndingHere, maxSoFar); 28 | } 29 | 30 | return maxSoFar; 31 | } 32 | 33 | //Time Complexity - O(n) 34 | //Traverses the array only once 35 | -------------------------------------------------------------------------------- /DynamicProgramming/LargestSquareSubMatrixOf1.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/find-size-largest-square-sub-matrix-1s-present-given-binary-matrix/ 3 | 4 | */ 5 | 6 | //Bottom up DP 7 | 8 | public int maxSizeOfSquareSubMatrix(int A[][]){ 9 | int n = A.length; 10 | int m = A[0].length; 11 | 12 | //dp[i][j] indicates the side-length of the largest square sub-matrix formed when (i,j) is the bottom-right corner of that sub-matrix 13 | int dp[][] = new int[n][m]; 14 | 15 | int maxSize = 0; 16 | 17 | for(int i=0;i0 && j>0 && A[i][j]==1){ 24 | //dp[i-1][j] --> Top cell 25 | //dp[i][j-1] --> left cell 26 | //dp[i-1][j-1] --> top left cell 27 | //we chose the minimum value because it is the LIMITING VALUE and we can not have a square sub-matrix 28 | //of length greater than this minimum value 29 | dp[i][j] = Math.min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1; 30 | } 31 | 32 | maxSize = Math.max(maxSize, dp[i][j]); 33 | } 34 | } 35 | 36 | return maxSize; 37 | 38 | } 39 | 40 | /* 41 | Time and Space Complexity - O(n*m) 42 | */ 43 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestBitonicSubsequence/LengthOfLongestBitonicSubsequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/longest-bitonic-subsequence/ 3 | https://youtu.be/TWHytKnOPaQ 4 | 5 | Bitonic Subsequence - It is a subsequence which first increases and then decreases.(strictly) 6 | This problem uses the same concept as the problem - Longest Increasing Subsequence 7 | 8 | We maintain two arrays - I[] and D[] 9 | For each index i in the input array, 10 | I[i] indicates the length of the longest increasing subsequence starting from 0 and ending at i 11 | D[i] indicates the length of the longest increasing subsequence starting from end of the input array and ending at i 12 | 13 | */ 14 | 15 | public int lengthOfLongestBitonicSubseq(int A[]){ 16 | int n = A.length; 17 | 18 | int I[] = new int[n]; 19 | int D[] = new int[n]; 20 | 21 | //Initialization 22 | I[0] = 1; 23 | D[n-1] = 1; 24 | 25 | //starting from the start of the array 26 | for(int i=1 ; i < n ; i++){ 27 | I[i] = 1; 28 | 29 | //for all elements occuring before A[i], check if they can be included to form an increasing subseq ending at i 30 | for(int j=0 ; j < i ; j++){ 31 | if(A[j] < A[i]){ 32 | //Chose max value 33 | I[i] = Math.max(I[i], I[j]+1); 34 | } 35 | } 36 | } 37 | 38 | //starting from the end of the array 39 | //Increasing subseq from end --> decreasing subseq from start 40 | for(int i=n-2 ; i >= 0 ; i--){ 41 | D[i] = 1; 42 | 43 | //for all elements occuring after A[i], check if they can be included to form an increasing subseq ending at i 44 | for(int j=n-1 ; j > i ; j--){ 45 | if(A[i] > A[j]){ 46 | D[i] = Math.max(D[i], D[j]+1); 47 | } 48 | } 49 | } 50 | 51 | //Find length of longest bitonic subseq 52 | int maxLen = 0; 53 | for(int i=0 ; i < n ; i++){ 54 | //subtract 1 --> i is included twice, both in I and D 55 | if(maxLen < I[i] + D[i] - 1) maxLen = I[i] + D[i] - 1; 56 | } 57 | 58 | return maxLen; 59 | } 60 | 61 | //Time Complexity - O(n^2) 62 | //Space Complexity - O(n) 63 | 64 | 65 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestBitonicSubsequence/PrintLongestBitonicSubsequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/longest-bitonic-subsequence/ 3 | 4 | */ 5 | 6 | public void lengthOfLongestBitonicSubseq(int A[]){ 7 | int n = A.length; 8 | 9 | //Instead of storing max length of subseq, we store the entire subseq 10 | List> I = new ArrayList<>(); 11 | List> D = new ArrayList<>(); 12 | 13 | for(int i = 0 ; i < n ; i++){ 14 | I.add(new ArrayList()); 15 | D.add(new ArrayList()); 16 | } 17 | 18 | //Initialization 19 | I.get(0).add(A[0]); 20 | D.get(n-1).add(A[n-1]); 21 | 22 | //starting from the start of the array 23 | for(int i=1 ; i < n ; i++){ 24 | 25 | //for all elements occuring before A[i], check if they can be included to form an increasing subseq ending at i 26 | for(int j=0 ; j < i ; j++){ 27 | //comparing the array elements and the length of longest increasing subseq 28 | if(A[j] < A[i] && I.get(i).size() < I.get(j).size()){ 29 | I.set(i, new ArrayList<>(I.get(j))); 30 | } 31 | } 32 | //add current element at the end of the subseq 33 | I.get(i).add(A[i]); 34 | } 35 | 36 | //starting from the end of the array 37 | //Increasing subseq from end --> decreasing subseq from start 38 | for(int i=n-2 ; i >= 0 ; i--){ 39 | 40 | //for all elements occuring after A[i], check if they can be included to form an increasing subseq ending at i 41 | for(int j=n-1 ; j > i ; j--){ 42 | if(A[i] > A[j] && D.get(j).size() > D.get(i).size()){ 43 | D.set(i, new ArrayList<>(D.get(j))); 44 | } 45 | } 46 | //add current element to the start of the subseq 47 | D.get(i).add(0, A[i]); 48 | } 49 | 50 | //Find length of longest bitonic subseq 51 | int maxInd = 0; 52 | for(int i=1 ; i < n ; i++){ 53 | //subtract 1 --> i is included twice, both in I and D 54 | if(I.get(maxInd).size() + D.get(maxInd).size() < I.get(i).size() + D.get(i).size()) maxInd = i; 55 | } 56 | 57 | //Print increasing subseq 58 | System.out.print(I.get(maxInd)); 59 | //This element is repeated --> remove it 60 | D.get(maxInd).remove(0); 61 | //Print decreasing subseq 62 | System.out.print(D.get(maxInd)); 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestCommonSubsequence/Find_Longest_Common_Subsequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/longest-common-subsequence-finding-lcs/ 3 | Start from bottom right corner and make your way up to the top left corner. 4 | Logic to find one LCS - 5 | 1. If the current characters are equal, append the character to the solution string and move up along the left diognal. 6 | 2. If the current characters are not equal, we go top or left depending on which cell holds the maximum value. 7 | */ 8 | 9 | class LCS{ 10 | 11 | public String lcs(String a, String b, int n, int m, int matrix[][]){ 12 | if(n==0 || m==0) return ""; 13 | 14 | if(a.charAt(n-1)==b.charAt(m-1)){ 15 | return ( lcs(a,b,n-1,m-1,matrix) + a.charAt(n-1) ); 16 | } 17 | else if(matrix[n-1][m] > matrix[n][m-1]){ 18 | return lcs(a,b,n-1,m,matrix); 19 | } 20 | else{ 21 | return lcs(a,b,n,m-1,matrix); 22 | } 23 | } 24 | 25 | public int LCSlength(String a, String b, int n, int m, int lcs[][]){ 26 | 27 | for(int i=0;i<=n;i++) lcs[i][0] = 0; 28 | for(int j=0;j<=m;j++) lcs[0][j] = 0; 29 | 30 | for(int i=1;i<=n;i++){ 31 | for(int j=1;j<=m;j++){ 32 | if(a.charAt(i-1)==b.charAt(j-1)){ 33 | lcs[i][j] = lcs[i-1][j-1] + 1; 34 | } 35 | 36 | else{ 37 | lcs[i][j] = Math.max(lcs[i-1][j], lcs[i][j-1]); 38 | } 39 | } 40 | } 41 | return lcs[n][m]; 42 | 43 | } 44 | 45 | } 46 | 47 | 48 | /* 49 | Logic to find all LCSs - 50 | 1. If the current characters are equal, append the character to the solution string and move up along the left diognal. 51 | 2. If the current characters are not equal, we go top or left depending on which cell holds the maximum value. 52 | 2.1. If both the cells hold the same value we explore them both 53 | */ 54 | 55 | class LCS{ 56 | 57 | public List lcs(String a, String b, int n, int m, int matrix[][]){ 58 | if(n==0 || m==0){ 59 | List list = new ArrayList(); 60 | list.append(""); 61 | return list; 62 | } 63 | 64 | if(a.charAt(n-1)==b.charAt(m-1)){ 65 | List list = lcs(a,b,n-1,m-1,matrix); 66 | 67 | for(int i=0;i matrix[n][m-1]){ 74 | return lcs(a,b,n-1,m,matrix); 75 | } 76 | else if(matrix[n-1][m] < matrix[n][m-1]){ 77 | return lcs(a,b,n,m-1,matrix); 78 | } 79 | else{ 80 | List top = lcs(a,b,n-1,m,matrix); 81 | List left = lcs(a,b,n,m-1,matrix); 82 | 83 | top.addAll(left); 84 | return top; 85 | } 86 | 87 | } 88 | 89 | public int LCSlength(String a, String b, int n, int m, int lcs[][]){ 90 | 91 | for(int i=0;i<=n;i++) lcs[i][0] = 0; 92 | for(int j=0;j<=m;j++) lcs[0][j] = 0; 93 | 94 | for(int i=1;i<=n;i++){ 95 | for(int j=1;j<=m;j++){ 96 | if(a.charAt(i-1)==b.charAt(j-1)){ 97 | lcs[i][j] = lcs[i-1][j-1] + 1; 98 | } 99 | 100 | else{ 101 | lcs[i][j] = Math.max(lcs[i-1][j], lcs[i][j-1]); 102 | } 103 | } 104 | } 105 | return lcs[n][m]; 106 | 107 | } 108 | 109 | //to avoid duplicates 110 | public Set LCSset(String a, String b, int matrix[][]){ 111 | LCSlength(a,b,a.length(),b.length(),matrix); 112 | 113 | ArrayList list = lcs(a,b,a.length(),b.length(),matrix); 114 | 115 | return new HashSet<>(list); 116 | } 117 | 118 | } 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestIncreasingPathInMatrix.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/longest-increasing-path-matrix/ 3 | 4 | Given a matrix of N rows and M columns. From m[i][j], we can move to m[i+1][j], if m[i+1][j] > m[i][j], or can move to m[i][j+1] if m[i][j+1] > m[i][j]. The task is print longest path length if we start from (0, 0). 5 | 6 | Examples: 7 | 8 | Input : N = 4, M = 4 9 | m[][] = { { 1, 2, 3, 4 }, 10 | { 2, 2, 3, 4 }, 11 | { 3, 2, 3, 4 }, 12 | { 4, 5, 6, 7 } }; 13 | Output : 7 14 | Longest path is 1 2 3 4 5 6 7. 15 | 16 | Input : N = 2, M =2 17 | m[][] = { { 1, 2 }, 18 | { 3, 4 } }; 19 | Output :3 20 | Longest path is either 1 2 4 or 21 | 1 3 4. 22 | 23 | */ 24 | 25 | //RECURSION USING MEMOIZATION - DYNAMIC PROGRAMMING 26 | 27 | public int longestPathLength(int dp[][], int mat[][], int n, int m, int row, int col){ 28 | if(dp[row][col]==0){ 29 | //if the current call has been made, it means this cell is valid and should be considered in the sequence 30 | //The current cell is valid, but it might not be possible to move right/down so store the minimum result 31 | int result = 1; 32 | 33 | //if we can go down in the matrix and if that cell satisfies the property - explore 34 | if(row+1 42 | //EACH CALL INDICATES A VALID CELL 43 | 44 | dp[row][col] = result; 45 | } 46 | return dp[row][col]; 47 | } 48 | 49 | /* 50 | Time Complexity - O(n*m) 51 | Number of subproblems - n*m 52 | */ 53 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestIncreasingPathInMatrix/LongestIncreasingPathInMatrix.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/longest-increasing-path-matrix/ 3 | Given a matrix of N rows and M columns. From m[i][j], we can move to m[i+1][j], if m[i+1][j] > m[i][j], or can move to m[i][j+1] if m[i][j+1] > m[i][j]. The task is print longest path length if we start from (0, 0). 4 | Examples: 5 | Input : N = 4, M = 4 6 | m[][] = { { 1, 2, 3, 4 }, 7 | { 2, 2, 3, 4 }, 8 | { 3, 2, 3, 4 }, 9 | { 4, 5, 6, 7 } }; 10 | Output : 7 11 | Longest path is 1 2 3 4 5 6 7. 12 | Input : N = 2, M =2 13 | m[][] = { { 1, 2 }, 14 | { 3, 4 } }; 15 | Output :3 16 | Longest path is either 1 2 4 or 17 | 1 3 4. 18 | */ 19 | 20 | //RECURSION USING MEMOIZATION - DYNAMIC PROGRAMMING 21 | 22 | public int longestPathLength(int dp[][], int mat[][], int n, int m, int row, int col){ 23 | if(dp[row][col]==0){ 24 | //if the current call has been made, it means this cell is valid and should be considered in the sequence 25 | //The current cell is valid, but it might not be possible to move right/down so store the minimum result 26 | int result = 1; 27 | 28 | //if we can go down in the matrix and if that cell satisfies the property - explore 29 | if(row+1 37 | //EACH CALL INDICATES A VALID CELL 38 | 39 | dp[row][col] = result; 40 | } 41 | return dp[row][col]; 42 | } 43 | 44 | /* 45 | Time Complexity - O(n*m) 46 | Number of subproblems - n*m 47 | */ 48 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestIncreasingSubsequence/Find_Longest_Increasing_Subsequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/longest-increasing-subsequence-using-dynamic-programming/ 3 | REFER - Length of Longest Increasing Subsequence Code 4 | */ 5 | 6 | public void printLIS(int A[]){ 7 | List> LIS = new ArrayList(); 8 | 9 | for(int i=0 ; i()); 10 | 11 | //LIS of A[0] is itself 12 | LIS.get(0).add(A[0]); 13 | 14 | for(int i=1 ; i(LIS.get(j))); 18 | } 19 | } 20 | LIS.get(i).add(A[i]); 21 | } 22 | 23 | int index = 0; 24 | for(int i=1 ; i= 0 ; i--){ 29 | for(int j = i ; j < n ; j++){ 30 | //condition (2) and (3) 31 | isPalin[i][j] = (s.charAt(i) == s.charAt(j)) && ((j - i + 1 < 3) || isPalin[i+1][j-1]); 32 | 33 | //storing the longest palindromic substring 34 | if(isPalin[i][j] && (res == null || j - i + 1 > res.length())){ 35 | res = s.substring(i, j+1); 36 | } 37 | } 38 | } 39 | 40 | return res; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /DynamicProgramming/LongestRepeatedSubsequenceProblem.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/longest-repeated-subsequence-problem/ 3 | 4 | The problem is a modification of Longest Common Subsequence Problem. Here, we take both the strings to be the same and then find the Longest Common Subsequence. 5 | 6 | The Recurrence is almost the same as LCS - 7 | LRS[i][j] = 0 if i = 0 || j = 0 8 | = LRS[i-1][j-1] + 1 if (i != j) && s[i] == s[j] 9 | = max(LRS[i-1][j], LRS[i][j-1]) if s[i] != s[j] 10 | i and j can not have the same index as they represent the indixes of the same string. 11 | 12 | Normal Recursion would require exponential time and in worst case - NONE OF THE CHARACTERS REPEAT - time complexity turns out to be O(2^n). Each call further makes two other calls. 13 | 14 | */ 15 | 16 | 17 | //Memoized Recursion 18 | 19 | public int LRSlen(String s, int i, int j, HashMap map){ 20 | if(i==0 || j==0) return 0; //nothing to check of repetition - we have exhausted the string 21 | 22 | String key = i+"|"+j; 23 | 24 | if(!map.containsKey(key)){ 25 | if(i!=j && s.charAt(i-1) == s.charAt(j-1)){ 26 | map.put(key, LRSlen(s, i-1, j-1, map) + 1); 27 | } 28 | else{ 29 | map.put(key, Math.max(LRSlen(s, i-1, j, map), LRSlen(s, i, j-1, map))); 30 | } 31 | } 32 | return map.get(key); 33 | } 34 | //Time & Space Complexity - O(n^2) 35 | 36 | 37 | //Bottom Up DP 38 | 39 | public int LRSlen(String s){ 40 | int n = s.length(); 41 | 42 | //len[i][j] indicates the length of the LRS of s[0...i-1] and s[0...j-1] 43 | int len[][] = new int[n+1][n+1]; 44 | 45 | for(int i=1 ; i < n ; i++){ 46 | for(int j=1 ; j < n ; j++){ 47 | if( i!=j && s.charAt(i-1) == s.charAt(j-1) ){ 48 | len[i][j] = len[i-1][j-1] + 1; 49 | } 50 | else len[i][j] = Math.max(len[i][j-1], len[i-1][j]); 51 | } 52 | } 53 | 54 | return len[n][n]; 55 | } 56 | 57 | /* 58 | Time Complexity - O(n^2) 59 | Space Complexity - O(n^2) --> can be further optimized to O(n) [we only require the values from the previous rows] 60 | */ 61 | 62 | //Print the LRS --> Assuming we already have the 2D len[][] array with us 63 | 64 | public String printLRS(String s, int i, int j, int len[][]){ 65 | if(i==0 || j==0) return ""; 66 | 67 | if(i!=j && s.charAt(i-1) == s.charAt(j-1)){ 68 | return printLRS(s, i-1, j-1, len) + s.charAt(i-1); 69 | } 70 | else{ 71 | if(len[i-1][j] > len[i][j-1]){ 72 | return printLRS(s, i-1, j, len); 73 | } 74 | else{ 75 | return printLRS(s, i, j-1, len); 76 | } 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /DynamicProgramming/MaxRectangularSubmatrixOf1s.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://github.com/mission-peace/interview/blob/master/src/com/interview/stackqueue/MaximumHistogram.java 3 | https://github.com/mission-peace/interview/blob/master/src/com/interview/dynamic/MaximumRectangularSubmatrixOf1s.java 4 | 5 | We use the max-rectangular area in a histogram here. Explanantion of problem - 6 | Input - An array --> each element represents the height of a bar in the histogram 7 | Ouput - maximum possible area in the histogram 8 | 9 | We use the above code to find the maximal size rectangular sub-matrix of 1s. 10 | We maintain a 1D array of all values from a row and keep adding the values from the previous rows when the value!=0 11 | Then we apply the histogram code to find the max area rectangle. 12 | */ 13 | 14 | class Solution{ 15 | 16 | public int maxRectSubmatrix(int A[][]){ //Time Complexity - O(n*m) 17 | int n = A.length; 18 | int m = A[0].length; 19 | 20 | int maxArea = 0; 21 | 22 | //temporary array used for computation with maxHistogram 23 | //we keep adding column values as we move down the rows but reset if value in A = 0 24 | int temp[] = new int[m]; 25 | 26 | for(int i=0;i stk = new Stack(); 41 | 42 | int maxArea = 0; 43 | int area = 0; 44 | 45 | //i indicates the length of the histogram's base considered so far 46 | int i = 0; 47 | 48 | while(i < A.length){ 49 | // we can push a new value when stack is empty or the value on top of stack is smaller or equal to the current value 50 | //this ensures all values in the stack are in (non-decreasing order)ascending order 51 | if(stk.isEmpty() || A[stk.peek()] <= A[i]) stk.push(i++); 52 | 53 | else{ 54 | int top = stk.pop(); 55 | 56 | //this is the smallest element in the entire array --> 57 | //we can safely multiply it with the length of the histogram base --> max base length = i 58 | if(stk.isEmpty()) area = A[top] * i; 59 | 60 | //maximum base length = (i - stk.peek() - 1) 61 | //this means for the range (stk.peek(), i) both exclusive, the minimum(height of the bar) = A[top] 62 | else area = A[top] * (i - stk.peek() - 1); 63 | } 64 | maxArea = Math.max(maxArea, area); 65 | } 66 | 67 | //the stack might not be empty so we apply the same logic to the remainimg elements of the stack 68 | while(!stk.isEmpty()){ 69 | int top = stk.pop(); 70 | 71 | if(stk.isEmpty()) area = A[top]*i; 72 | else area = A[top] * (i - stk.peek() - 1); 73 | 74 | maxArea = Math.max(maxArea, area); 75 | } 76 | 77 | return maxArea; 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /DynamicProgramming/MaximumProductCutting.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/maximum-product-cutting-dp-36/ 3 | 4 | Given a rope of length n meters, cut the rope in different parts of integer lengths in a way that maximizes product of lengths of all parts. You must make at least one cut. Assume that the length of rope is more than 2 meters. 5 | 6 | Examples: 7 | 8 | Input: n = 2 9 | Output: 1 (Maximum obtainable product is 1*1) 10 | 11 | Input: n = 3 12 | Output: 2 (Maximum obtainable product is 1*2) 13 | 14 | Input: n = 4 15 | Output: 4 (Maximum obtainable product is 2*2) 16 | 17 | Input: n = 5 18 | Output: 6 (Maximum obtainable product is 2*3) 19 | 20 | Input: n = 10 21 | Output: 36 (Maximum obtainable product is 3*3*4) 22 | 23 | 24 | OPTIMAL SUBSTRUCTURE 25 | Try all possible cuts and divide current length into 2 parts. Then recursivley call the 'dividing function' on one of the parts to find the best solution. 26 | 27 | OVERLAPPING SUBPROBLEMS 28 | 29 | RECURRENCE - 30 | maxProd(n) = max( i*(n-i) , i*maxProd(n-i) ) for i in [1....n-1] 31 | */ 32 | 33 | //RECURSIVE SOLUTION 34 | public int maxProd(int rodLength){ 35 | 36 | //minimum length of 2 is required if we are supposed to make atleast 2 partitions 37 | if(rodLength==0 || rodLength==1) return 0; 38 | 39 | int maxP = 0; 40 | 41 | //trying partitions of all lengths [1...length-1] 42 | for(int len=1 ; len < rodLength ; len++){ 43 | 44 | /* 45 | For the current partition length which is the best? 46 | leaving it here, making this the last division into 2 ==> len * (rodLength-len) OR 47 | exploring further ==> len * maxProd(rodLength-len) Here only one of the partition is broken down(rodLength-len) further 48 | because the other part will be considered eventually because of the loop. 49 | */ 50 | int currMaxP = Math.max( len*(rodLength-len), len*maxProd(rodLength-len) ); 51 | 52 | //to chose the best out of all the partitions 53 | maxP = Math.max(maxP, currMaxP); 54 | 55 | } 56 | 57 | return maxP; 58 | } 59 | 60 | 61 | //DYNAMIC PROGRAMMING - MEMOIZATION 62 | 63 | public int maxProd(int rodLength){ 64 | 65 | //maxP[i] indicates the maximum product obtained if length=i 66 | int maxP[] = new int[rodLength+1]; 67 | 68 | maxP[0] = 0; 69 | maxP[1] = 0; 70 | 71 | for(int len=2;len<=rodLength;len++){ 72 | int currMaxP = 0; 73 | for(int j=1 ; j 4) 101 | { 102 | n -= 3; 103 | 104 | // Keep multiplying 3 to res 105 | res *= 3; 106 | } 107 | 108 | // The last part multiplied by 109 | // previous parts 110 | return (n * res); 111 | } 112 | 113 | -------------------------------------------------------------------------------- /DynamicProgramming/MaximumSumIncreasingSubsequence/MaxSumIncreasingSubseq.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/increasing-subsequence-with-maximum-sum/ 3 | 4 | Basically the same as the problem - Longest Increasing Subsequence - Instead of storing the max length, we store the max sum. 5 | 6 | The problem is to find the maximum sum possible after considering all increasing subsequences. 7 | */ 8 | 9 | public int maxSumOfIncSubseq(int A[]){ 10 | int n = A.length; 11 | 12 | //sum[i] indicates the sum of the increasing subsequence formed ending at i 13 | int sum[] = new int[n]; 14 | 15 | sum[0] = A[0]; 16 | 17 | for(int i = 1 ; i < n ; i++){ 18 | //for each index i we consider all elements before it 19 | for(int j = 0 ; j < i ; j++){ 20 | 21 | //check for increasing subsequence and greater sum 22 | if(A[j] < A[i] && sum[i] < sum[j]){ 23 | sum[i] = sum[j]; 24 | } 25 | } 26 | //since the subsequence ends in A[i] add the value of that element as well 27 | sum[i] += A[i]; 28 | } 29 | 30 | //find max sum 31 | int maxSum = 0; 32 | for(int i=0 ; i < n ; i++){ 33 | if(maxSum < sum[i]) maxSum = sum[i]; 34 | } 35 | 36 | return maxSum; 37 | 38 | } 39 | 40 | /* 41 | Time Complexity - O(n^2) 42 | Space Complexity - O(n) 43 | */ 44 | -------------------------------------------------------------------------------- /DynamicProgramming/MaximumSumIncreasingSubsequence/PrintMaxSumIncreasingSubseq.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/increasing-subsequence-with-maximum-sum/ 3 | 4 | */ 5 | 6 | public void printMaxSumIncreasingSubseq(int A[]){ 7 | int n = A.length; 8 | 9 | int sum[] = new int[n]; 10 | sum[0] = A[0]; 11 | 12 | //to store the subseq 13 | List> msis = new ArrayList(); 14 | 15 | for(int i=0;i()); 17 | } 18 | 19 | //Initialization 20 | msis.get(0).add(A[0]); 21 | 22 | 23 | for(int i=1 ; i < n ; i++){ 24 | for(int j=0 ; j < i ; j++){ 25 | //update the value of sum and the corresponding subseq 26 | if(A[j] < A[i] && sum[i] < sum[j]){ 27 | sum[i] = sum[j]; 28 | msis.set(i, new ArrayList(msis.get(j))); 29 | } 30 | } 31 | //add the last value to the sum 32 | sum[i] += A[i]; 33 | msis.get(i).add(A[i]); 34 | } 35 | 36 | int index = 0; 37 | for(int i=1;i choose the maximum 46 | sum[i] = Math.max(sum[i], A[i]); 47 | } 48 | 49 | return sum[n-1]; 50 | 51 | } 52 | 53 | //Time and Space Complexity - O(n) 54 | 55 | //We require only two variables to compute current sum and not entire array 56 | public int maxSumOfSubseqNonAdj(int A[]){ 57 | int n = A.length; 58 | 59 | if(n == 1) return A[0]; 60 | 61 | int prevPrevSum = A[0]; 62 | int prevSum = Math.max(A[0], A[1]); 63 | 64 | for(int i = 2 ; i < n ; i++){ 65 | int exc = prevSum; 66 | int inc = prevPrevSum + A[i]; 67 | 68 | int currSum = Math.max(inc, exc); 69 | 70 | //Usefull if both inc, exc and A[i] are negative --> choose the maximum 71 | currSum = Math.max(currSum, A[i]); 72 | 73 | //Update previous values 74 | prevPrevSum = prevSum; 75 | prevSum = currSum; 76 | } 77 | 78 | return prevSum; 79 | } 80 | 81 | //Time Complexity - O(n) 82 | //Space Complexity - O(1) 83 | 84 | -------------------------------------------------------------------------------- /DynamicProgramming/MaximumSumRectangularSubMatrix.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://youtu.be/yCQN096CwWM 3 | https://github.com/mission-peace/interview/blob/master/src/com/interview/dynamic/SubRectangularMatrixWithMaximumSum.java 4 | 5 | We Use Kadane's Algorithm to solve this problem 6 | */ 7 | 8 | class MaxSumRectangularSubMatrix{ 9 | class Result{ 10 | int maxSum; 11 | int leftBound; 12 | int rightBound; 13 | int lowBound; 14 | int upBound; 15 | } 16 | 17 | class KadaneResult{ 18 | int sum; 19 | int start; //will indicate the start row of the max sum sub matrix 20 | int end; //will indicate the end row of the max sum sub matrix 21 | } 22 | 23 | 24 | public Result maxSum(int A[][]){ 25 | int rows = A.length; 26 | int cols = A[0].length; 27 | 28 | int kadaneCol[] = new int[rows]; 29 | Result result = new Result(); 30 | 31 | //we set a new start boundary for the sub-matrix --> this is the left boundary 32 | for(int left=0 ; left < cols ; left++){ 33 | 34 | //Clear the previous values 35 | Arrays.fill(kadaneCol,0); //O(n) 36 | 37 | //the left boundary is set, but we move the right boundary towards the end of the matrix 38 | for(int right=left ; right < cols ; right++){ 39 | 40 | //add values from the newly shifted right boundary 41 | //This is done because we are applying Kadane's Algorithm which works on 1D arrays 42 | //We pass an array(to the kadane's algorithm) containing cummulative sum of each row(which makes the array 1D) 43 | //Kadane's algo finds the max sum subarray from this array --> This is nothing but the max sum sub matrix 44 | //left and right are set in this function and Kadane's algo helps to fix the up and low. 45 | for(int i=0;i result.maxSum){ 52 | result.maxSum = kadaneResult.sum; 53 | result.leftBound = left; 54 | result.rightBound = right; 55 | result.upBound = kadaneResult.start; 56 | result.lowBound = kadaneResult.end; 57 | } 58 | } 59 | } 60 | 61 | return result; 62 | 63 | } 64 | 65 | /* 66 | Time Complexity - O((col^2)*row) --> cubic 67 | Space Complexity - O(row) 68 | */ 69 | 70 | public KadaneResult kadane(int A[]){ //to return the maxSum, start and end in linear time 71 | int n = A.length; 72 | 73 | if(n == 0) return 0; 74 | 75 | KadaneResult kr = null; 76 | 77 | int maxEndingHere = A[0]; 78 | int maxSoFar = A[0]; 79 | int maxStart = 0; 80 | int start = 0; 81 | int maxEnd = 0; 82 | 83 | for(int i=1 ; i < n ; i++){ 84 | //include current element in the sub-array sum 85 | maxEndingHere+=A[i]; 86 | 87 | //check if starting a new sub-array gives a greater sum than the current sum 88 | if(maxEndingHere < A[i]){ 89 | start = i; 90 | maxEndingHere = A[i]; 91 | } 92 | 93 | //update the overall max-sum 94 | if(maxSoFar < maxEndingHere){ 95 | maxSoFar = maxEndingHere; 96 | maxEnd = i; 97 | maxStart = start; 98 | } 99 | } 100 | 101 | return new KadaneResult(maxSoFar, maxStart, maxEnd); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /DynamicProgramming/MaximumSumSubMatrixInAGivenMatrix.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/find-maximum-sum-submatrix-in-given-matrix/ 3 | First read - https://www.techiedelight.com/calculate-sum-elements-sub-matrix-constant-time/ 4 | Extenstion of the problem - Calculate Sum of All Elements in a Submatrix in constant time 5 | 6 | In this problem we are supposed to find maximum sum of a submatrix of size k*k 7 | 8 | */ 9 | 10 | class Point{ 11 | int x; 12 | int y; 13 | 14 | Point(int i, int j){ 15 | x = i; 16 | y = j; 17 | } 18 | 19 | } 20 | 21 | class SubMatrix{ 22 | int sum[][]; 23 | 24 | public void fillSumMatrix(int A[][]){ 25 | int n = A.length; 26 | int m = A[0].length; 27 | 28 | sum = new int[n][m]; 29 | 30 | sum[0][0] = A[0][0]; 31 | 32 | //pre-process first row 33 | for(int j=1 ; j < m ; j++){ 34 | sum[0][j] = sum[0][j-1] + A[0][j]; 35 | } 36 | 37 | //pre-process first col 38 | for(int i=1 ; i < n ; i++){ 39 | sum[i][0] = sum[i-1][0] + A[i][0]; 40 | } 41 | 42 | //compute rest of the sum-matrix 43 | for(int i=1 ; i < n ; i++){ 44 | for(int j=1 ; j < m ; j++){ 45 | sum[i][j] = A[i][j] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]; 46 | } 47 | } 48 | } 49 | 50 | public Point maxSumSubmatrix(int k){ //returns the bottom right corner of the maximum sum submatrix 51 | //dimensions of the required submatrix --> (k*k) 52 | 53 | //dimensions of main matrix 54 | int n = sum.length; 55 | int m = sum[0].length; 56 | 57 | int currSum = 0; 58 | int maxSum = 0; 59 | Point p = null; 60 | 61 | for(int i=k-1 ; i < n ; i++){ 62 | for(int j=k-1 ; j < m ; j++){ 63 | 64 | currSum = sum[i][j]; 65 | 66 | if(i-k >= 0){ 67 | result -= sum[i-k][j]; 68 | } 69 | if(j-k >= 0){ 70 | result -= sum[i][j-k]; 71 | } 72 | if(i-k >= 0 && j-k >= 0){ 73 | result += sum[i-k][j-k]; 74 | } 75 | 76 | if(maxSum < currSum){ 77 | maxSum = currSum; 78 | p = new Point(i,j); 79 | } 80 | } 81 | } 82 | return p; 83 | 84 | } 85 | 86 | } 87 | 88 | 89 | -------------------------------------------------------------------------------- /DynamicProgramming/MinCostToReachLastCellFromFirstCellMatrix.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/find-minimum-cost-reach-last-cell-matrix-first-cell/ 3 | 4 | From the first cell reach the last cell. Each cell has a cost. Minimize total cost. 5 | Allowed moves - right and bottom --> from (i,j) valid moves are --> (i+1,j) and (i,j+1) 6 | (Further) - consider diaognal moves as well 7 | 8 | 9 | Optimal substructure - 10 | cost to reach(i,j) = cost[i][j] + min( cost to reach(i-1,j), cost to reach(i,j-1) ) 11 | 12 | Overlapping subproblems 13 | 14 | Recursive Solution 15 | */ 16 | 17 | public int minCost(int cost[][], int row, int col){ 18 | //row or col has reached an invalid value 19 | if(row==0 || col==0) return Integer.MAX_VALUE; 20 | 21 | //we are at the first cell --> return its value 22 | else if(row==1 && col==1) return cost[row-1][col-1]; 23 | 24 | else return cost[row-1][col-1] + Math.min(minCost(cost, row-1, col), minCost(cost, row, col-1)); 25 | } 26 | 27 | //DP Bottom up approach 28 | 29 | public int minCost(int cost[][]){ 30 | int n = cost.length; 31 | int m = cost[0].length; 32 | 33 | //pathCost[i][j] denotes the minimum cost to reach the cell(i,j) form the first cell(0,0) 34 | int pathCost[][] = new int[n][m]; 35 | 36 | for(int i=0 ; i < n ; i++){ 37 | for(int j=0 ; j < m ; j++){ 38 | pathCost[i][j] = cost[i][j]; 39 | 40 | //to reach any cell in the first row the only possible way is from left 41 | if(i==0 && j>0){ 42 | pathCost[i][j]+=pathCost[i][j-1]; 43 | } 44 | 45 | //to reach any cell in the first column the only possible way is from top 46 | else if(j==0 && i>0){ 47 | pathCost[i][j]+=pathCost[i-1][j]; 48 | } 49 | 50 | //consider the path cost from the top and left --> choose minimum 51 | else{ 52 | pathCost[i][j]+=Math.min(pathCost[i-1][j],pathCost[i][j-1]); 53 | } 54 | } 55 | } 56 | 57 | //stores the minimum path cost 58 | return pathCost[n][m]; 59 | } 60 | 61 | /* 62 | Time and Space Complexity - O(n*m) 63 | 64 | */ 65 | -------------------------------------------------------------------------------- /DynamicProgramming/MinimumCutsForPalindromicPartition.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/find-minimum-cuts-needed-palindromic-partition-string/ 3 | https://youtu.be/WPr1jDh3bUQ 4 | */ 5 | 6 | //Bottom Up Dynamic Programming 7 | 8 | //Pre Computation - Bottom Up DP to find if substring is a palindrome or not 9 | public void findAllPlindromes(String s, boolean isPalin[][]){ 10 | //We only use the values above the principal diagonal 11 | //isPalin[i][j] stores if s[i..j] is a palindrome or not 12 | 13 | //we start from the end because we require the value of (i+1). 14 | for(int i = s.length() - 1 ; i >= 0 ; i--){ 15 | for(int j = i ; j < s.length() ; j++){ 16 | 17 | //single character is always a palindrome 18 | if(i == j) isPalin[i][j] = true; 19 | 20 | //if the border characters match --> check the inner string 21 | else if(s.charAt(i) == s.charAt(j)){ 22 | //if the length of the substring being considered is 2 --> directly put true 23 | //else check if the inner string [i+1 ... j-1] is a palindrome or not 24 | isPalin[i][j] = (j-i == 1) ? true : isPalin[i+1][j-1]; 25 | } 26 | 27 | //when the border characters don't match --> not possible to be a palindrome 28 | else isPlain[i][j] = false; 29 | } 30 | } 31 | 32 | } 33 | 34 | public int minCutsPlainPartition(String s, boolean isPlain[][]){ 35 | int n = s.length(); 36 | 37 | //cuts[i] indicates the minimum cuts required in s[0...i] to form palindrome partition 38 | int cuts[] = new int[n]; 39 | 40 | for(int i=0 ; i < n ; i++){ 41 | //check if the current substring is partition --> if it is a palindrome we need 0 cuts 42 | if(isPlain[0][i]) cuts[i] = 0; 43 | else{ 44 | int minCuts = Integer.MAX_VALUE; 45 | 46 | //we partition the substring s[0...i] at j into two substrings --> s[0...j] and s[j+1...i] 47 | //since we need to make palindromic partitions, we check if the 2nd substring s[j+1...i] is a palindrome or not 48 | //we are basically CHOOSING A PARTITION(j) WHICH KEEPS THE 2nd SUBSTRING AS IT IS(bacuse it is a palindrome) AND 49 | //DECOMPOSES THE 1ST SUBSTRING INTO SUBPROBLEMS TO FIND MINIMUM CUTS 50 | for(int j=0 ; j < i ; j++){ //j creates the partition 51 | 52 | //1. Check if 2nd substring is a palindrome 53 | //2. solve the subproblem --> we are using the bottom up appraoch, subproblem is already solved 54 | // subproblem is s[0...j] --> we solve it by considering cuts[j] 55 | //3. Consider all valid partitions and chose the cheapest 56 | if(isPalin[j+1][i] && minCuts > cuts[j]+1){ 57 | minCuts = cuts[j] + 1; 58 | } 59 | } 60 | cuts[i] = minCuts; 61 | } 62 | } 63 | 64 | //result for minimum cuts of s[0...n-1] 65 | return cuts[n-1]; 66 | } 67 | 68 | /* 69 | Time Complexity - O(n^2) 70 | Space Complexity - O(n^2) [n^2 to store isPlain and n to store cuts --> isPlain is more] 71 | */ 72 | 73 | -------------------------------------------------------------------------------- /DynamicProgramming/OptimalStratergyForGame/Optimal_Stratergy_For_Game.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/optimal-strategy-for-a-game-dp-31/ 3 | 4 | NOTE - Similar to Longest Palindromic Subsequence 5 | 6 | Consider a row of n coins of values v1 . . . vn, where n is even. We play a game against an opponent by alternating turns. In each turn, a player selects either the first or last coin from the row, removes it from the row permanently, and receives the value of the coin. Determine the maximum possible amount of money we can definitely win if we move first. 7 | 8 | 8, 15, 3, 7 : The user collects maximum value as 22(7 + 15) 9 | …….User chooses 7. 10 | …….Opponent chooses 8. 11 | …….User chooses 15. 12 | …….Opponent chooses 3. 13 | Total value collected by user is 22(7 + 15) 14 | 15 | 16 | There are two choices: 17 | 1. The user chooses the ith coin with value Vi: The opponent either chooses (i+1)th coin or jth coin. The opponent intends to choose the coin which leaves the user with minimum value. 18 | i.e. The user can collect the value Vi + min(F(i+2, j), F(i+1, j-1) ) 19 | 2. The user chooses the jth coin with value Vj: The opponent either chooses ith coin or (j-1)th coin. The opponent intends to choose the coin which leaves the user with minimum value. 20 | i.e. The user can collect the value Vj + min(F(i+1, j-1), F(i, j-2) ) 21 | 22 | F(i, j) represents the maximum value the user can collect from 23 | i'th coin to j'th coin. 24 | 25 | F(i, j) = Max(Vi + min(F(i+2, j), F(i+1, j-1) ), 26 | Vj + min(F(i+1, j-1), F(i, j-2) )) 27 | Base Cases 28 | F(i, j) = Vi If j == i 29 | F(i, j) = max(Vi, Vj) If j == i+1 30 | */ 31 | 32 | 33 | public int optimalStratergy(int coins[]){ 34 | int n = coins.length; 35 | 36 | //to store solutions to sub-problems ==> considering coins in varying ranges 37 | int T[][] = new int[n][n]; 38 | 39 | //values lying below the principal diaognal in T are not used. 40 | //T[i][j] indicates the maximum amount Player1 can earn if coins under consideration are from i....j 41 | //we maintain a variable 'gap' to indicate the number of coins under consideration 42 | //gap will range from 1...n 43 | //gap will also be used like a window, if gap=3 the elements under consideration will be coins[0...2], coins[1...3], ... 44 | 45 | //when gap=1, only one coin is considered and Player1 will pick that coin itself. 46 | //T[i][i] ==> single coin is considered 47 | for(int i=0;i coins[0],coins[1] 53 | T[1][2] ==> coins[1],coins[2] 54 | ... 55 | we can easily see gap is being slid by one each time. 56 | */ 57 | for(i=0;i=3 we use a nested for loop as here we will use the recurrence relation to fill the table. 60 | for(int gap=3 ; gap<=n ; gap++){ 61 | for(int start=0 ; start Player1 choses 20 and player2 chooses 10 18 | SUM(20,10,2) - 20 ) ==> Player1 chooses 2 and Player2 chooses 20 19 | 20 | 2.1. Player2 choses max out of two adjacent elements. The remaining is what Player1 gets. 21 | 22 | */ 23 | 24 | public int calcSum(int coins[]){ 25 | int sum = 0; 26 | int n = coins.length; 27 | int dp[][] = new int[n][n]; 28 | 29 | for(int i=0;i){ 37 | if(n==0 || m==0) return n+m; 38 | 39 | String key = n+"|"+m; 40 | 41 | if(!map.containsKey(key)){ 42 | if(X.charAt(n-1) == Y.charAt(m-1)) map.put(key, scsLength(X, Y, n-1, m-1, map)+1); 43 | else map.put(key, Math.min(scsLength(X, Y, n, m-1, map), scsLength(X, Y, n-1, m, map))+1); 44 | } 45 | return map.get(key); 46 | } 47 | /* 48 | Time Complexity and Space Complexity - O(n*m) 49 | */ 50 | 51 | //BOTTOM UP DYNAMIC PROGRAMMING 52 | /* 53 | SCS[i][j] = i if j==0 54 | = j if i==0 55 | = SCS[i-1][j-1] + 1 if(X[i] == Y[j]) 56 | = Math.min(SCS[i-1][j], SCS[i][j-1]) + 1 if(X[i] != Y[j]) 57 | */ 58 | 59 | public int scsLength(String X, String Y){ 60 | int n = X.length(); 61 | int m = Y.length(); 62 | int T[][] = new int[n+1][m+1]; 63 | 64 | for(int i=0 ; i <=n ; i++) T[i][0] = i; 65 | for(int j=0 ; j <= m ; j++) T[0][j] = j; 66 | 67 | for(int i=1;i<=n;i++){ 68 | for(int j=1;j<=m;j++){ 69 | if(X.charAt(i-1) == Y.charAt(j-1)) T[i][j] = T[i-1][j-1]+1; 70 | else T[i][j] = Math.min(T[i-1][j], T[i][j-1])+1 71 | } 72 | } 73 | 74 | return T[n][m]; 75 | } 76 | 77 | /* 78 | Time Complexity & Space Complexity - O(n*m) 79 | */ 80 | 81 | //SPACE OPTIMIZED DYNAMIC PROGRAMMING - BOTTOM UP 82 | 83 | public int scsLength(String X, String Y){ 84 | int n = X.length(); 85 | int m = Y.length(); 86 | int T[][] = new int[2][m+1]; 87 | 88 | for(int i=0 ; i <=m ; i++) T[0][i] = i; 89 | 90 | for(int i=1;i<=n;i++){ 91 | for(int j=0;j<=m;j++){ 92 | if(j==0) T[i % 2][j] = i; 93 | else if(X.charAt(i-1) == Y.charAt(j-1)) T[i % 2][j] = T[(i-1) % 2][j-1]+1; 94 | else T[i % 2][j] = Math.min(T[(i-1) % 2][j], T[i % 2][j-1])+1 95 | } 96 | } 97 | 98 | return T[n % 2][m]; 99 | } 100 | 101 | /* 102 | Time Complexity - O(n*m) 103 | Space Complexity - (2*m) 104 | */ 105 | 106 | -------------------------------------------------------------------------------- /DynamicProgramming/ShortestCommonSupersequence/PrintShortestCommonSupersequence.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/shortest-common-supersequence-finding-scs/ 3 | */ 4 | 5 | //Find one Shortest Common Supersequence 6 | // length(X) = m and length(Y) = n 7 | 8 | public String findSCS(String X, String Y, int m, int n,int T[][]){ 9 | 10 | if(m == 0) return Y.substring(0,n); 11 | 12 | else if(n == 0) return X.substring(0,m); 13 | 14 | else if( X.charAt(n-1) == Y.charAt(m-1) ){ 15 | return findSCS(X, Y, m-1, n-1, T) + X.charAt(n-1); 16 | } 17 | else if( T[m-1][n] < T[m][n-1] ){ 18 | return findSCS(X, Y, m-1, n, T) + X.charAt(m-1); 19 | } 20 | else{ 21 | return findSCS(X, Y, m, n-1, T) + Y.charAt(n-1); 22 | } 23 | } 24 | 25 | //Print all Shortest Common Supersequence 26 | // length(X) = m and length(Y) = n 27 | 28 | public List findSCS(String X, String Y, int m, int n, int T[][]){ 29 | if( m == 0){ 30 | List l = new ArrayList<>(); 31 | l.add(Y.substring(0,n)); 32 | return l; 33 | } 34 | else if( n == 0){ 35 | List l = new ArrayList<>(); 36 | l.add(X.substring(0,m)); 37 | return l; 38 | } 39 | else if( X.charAt(m-1) == Y.charAt(n-1) ){ 40 | List scs = findSCS(X, Y, m-1, n-1, T); 41 | List res = new ArrayList<>(); 42 | for(String s : scs){ 43 | res.add(s+X.charAt(m-1)); 44 | } 45 | return res; 46 | } 47 | else if( T[m-1][n] < T[m][n-1] ){ 48 | List scs = findSCS(X, Y, m-1, n, T); 49 | List res = new ArrayList<>(); 50 | for(String s : scs){ 51 | res.add(s+X.charAt(m-1)); 52 | } 53 | return res; 54 | } 55 | else if( T[m-1][n] > T[m][n-1] ){ 56 | List scs = findSCS(X, Y, m, n-1, T); 57 | List res = new ArrayList<>(); 58 | for(String s : scs){ 59 | res.add(s+Y.charAt(n-1)); 60 | } 61 | return res; 62 | } 63 | else{ //T[m-1][n] == T[m][n-1] 64 | List top = findSCS(X, Y, m-1, n, T); 65 | List left = findSCS(X, Y, m, n-1, T); 66 | List res = new ArrayList<>(); 67 | for(String s : top){ 68 | res.add(s + X.charAt(m-1)); 69 | } 70 | for(String s : left){ 71 | res.add(s + Y.charAt(n-1)); 72 | } 73 | return res; 74 | } 75 | 76 | } 77 | 78 | 79 | // Function to fill lookup table by finding length of SCS of 80 | // sequences X[0..m-1] and Y[0..n-1] 81 | public static void SCSLength(String X, String Y, int m, int n, int[][] T) 82 | { 83 | // initialize first column of the lookup table 84 | for (int i = 0; i <= m; i++) { 85 | T[i][0] = i; 86 | } 87 | 88 | // initialize first row of the lookup table 89 | for (int j = 0; j <= n; j++) { 90 | T[0][j] = j; 91 | } 92 | 93 | // fill the lookup table in bottom-up manner 94 | for (int i = 1; i <= m; i++) 95 | { 96 | for (int j = 1; j <= n; j++) 97 | { 98 | // if current character of X and Y matches 99 | if (X.charAt(i - 1) == Y.charAt(j - 1)) { 100 | T[i][j] = T[i - 1][j - 1] + 1; 101 | } 102 | // else if current character of X and Y don't match 103 | else { 104 | T[i][j] = Integer.min(T[i - 1][j] + 1, T[i][j - 1] + 1); 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /DynamicProgramming/StringInterleaving.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/check-string-interleaving-two-given-strings/ 3 | https://github.com/mission-peace/interview/blob/master/src/com/interview/dynamic/TwoStringInterleavingToFormThird.java 4 | 5 | 6 | a) If first character of S matches with first character of X, we move one character ahead in X and S and recursively check. 7 | b) If first character of S matches with first character of Y, we move one character ahead in Y and S and recursively check. 8 | 9 | */ 10 | 11 | //For only recursion --> Worst Case Time Complexity - O(2^(n+m)) --> When both strings are the same 12 | //n and m are lengths of the two strings 13 | 14 | //MEMOIZED RECUSRION 15 | public boolean isInterleaving(String X, String Y, String S, HashMap map){ 16 | if(X.length() == 0 && Y.length() == 0 && S.length() == 0) return true; 17 | else if( X.length() + Y.length() != S.length() ) return false; 18 | 19 | String key = X + "|" + Y + "|" + S; 20 | 21 | if(!map.containsKey(key)){ 22 | boolean b1 = (X.length()!=0 && X.charAt(0)==S.charAt(0)) && isInterleaving(X.substring(1), Y, S.substring(1), map); 23 | boolean b2 = (Y.length()!=0 && Y.charAt(0)==S.charAt(0)) && isInterleaving(X, Y.substring(1), S.substring(1), map); 24 | map.put(key, (b1 || b2)); 25 | } 26 | return map.get(key); 27 | } 28 | 29 | //BOTTOM UP DP 30 | public boolean isInterleaving(String X, String Y, String S){ 31 | 32 | if(X.length()+Y.length() != S.length()) return false; 33 | 34 | //T[i][j] indicates if S( 0....(i+j-1) ) is an interleaving of X(0...i) and Y(0...j) 35 | int T[][] = new int[X.length()+1][Y.length()+1]; 36 | 37 | for(int i=0 ; i < X.length() ; i++){ 38 | for(int j=0 ; j < Y.length() ; j++){ 39 | 40 | //total length of S to be checked for interleaving when first i charachters from X and first j characters from Y are considered 41 | int l = i + j - 1; 42 | 43 | //is interleaving of two empty strings also an empty string? ==> True 44 | if(i==0 && j==0) T[i][j] = true; 45 | 46 | //when X is an empty string ==> Only check Y and S 47 | else if(i==0){ 48 | //Check is the current characters match? ==> If True, check the subproblem ==> 49 | //==> does Y(0...j-1) form an interleaving in S(0...j-1) 50 | //solution to current problem is true only when - 51 | // 1. current characters match 52 | // 2. the subproblem also forms an interleaving ie. the subproblem returns true 53 | if(Y.charAt(j-1) == S.charAt(l)) T[i][j] = T[i][j-1]; 54 | } 55 | 56 | else if(j==0){ 57 | if(X.charAt(i-1) == S.charAt(l)) T[i][j] = T[i-1][j]; 58 | } 59 | //checks if either of the current characters X[i-1] or Y[j-1] matches the current character from interleaved string S[l] 60 | else{ 61 | //If there is a match of current characters, solve the subproblem ie. T[i-1][j] or T[i][j-1] 62 | T[i][j] = (X.charAt(i-1) == S.charAt(l) ? T[i-1][j] : false) || (Y.charAt(j-1) == S.charAt(l) ? T[i][j-1] : false); 63 | } 64 | } 65 | } 66 | 67 | return T[X.length()][Y.length()]; 68 | } 69 | 70 | /* 71 | Time Complexity and Space Complexity - O(X.length()*Y.length()) 72 | 73 | */ 74 | -------------------------------------------------------------------------------- /DynamicProgramming/SubsetSumProblem/SubsetSumProblem.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.geeksforgeeks.org/subset-sum-problem-dp-25/ 3 | https://www.techiedelight.com/subset-sum-problem/ 4 | 5 | 6 | To Do - Print Subsets and Solve in O(sum) 7 | Further - Does this work on negative numbers? 8 | 9 | 10 | Given a set of non-negative integers, and a value sum, determine if there is a subset of the given set with sum equal to given sum. 11 | Example: 12 | Input: set[] = {3, 34, 4, 12, 5, 2}, sum = 9 13 | Output: True //There is a subset (4, 5) with sum 9. 14 | 15 | A Naive Approach would be to form all subsets and see if their sum equals the given sum. 16 | Number of subsets = 2^n 17 | Time rqd to check if the sum of subset equals the given sum = n (at most, becuase maximum size of subset can be n) 18 | Time Complexity - O(n 2^n) 19 | 20 | 21 | RECURSION 22 | We have two choices - 23 | 1. Include the current item and recur with remaining sum 24 | 2. Exclude current item and recur 25 | */ 26 | 27 | public boolean isSubset(int A[], int current, int sum){ 28 | //Base Case 1: sum == 0 29 | if( sum == 0 ) return true; 30 | 31 | //Base Case 2: we have exhausted all elements and sum is still not 0 32 | else if( n==0 && sum!=0 ) return false; 33 | 34 | //Does the current element's value exceed the remaining sum? ==> Current element has to be EXCLUDED 35 | if( A[current-1] > sum ) return isSubset(A, current-1, sum); 36 | 37 | //Explore both choices - Include and Exclude 38 | return (isSubset(A, current-1, sum) || isSubset(A, current-1, sum-A[current-1])); 39 | } 40 | 41 | /* 42 | Time Complexity - O(2^n) 43 | We explore two choices at each recursion. 44 | 45 | The above solution may try all subsets of given set in worst case. Therefore time complexity of the above solution is exponential. The problem is in-fact NP-Complete (There is no known polynomial time solution for this problem). 46 | */ 47 | 48 | //DYNAMIC PROGRAMMING - PSUEDOPOLYNOMIAL - BOTTOM-UP APPROACH 49 | 50 | public boolean isSubset(int A[], int n, int sum){ 51 | boolean T[][] = new boolean[n+1][sum+1]; 52 | 53 | //if sum = 0, then answer is true 54 | for(int i=0;i<=n;i++) T[i][0] = true; 55 | 56 | //if the set is input is an empty set 57 | for(int j=0;j<=sum;j++) T[0][j] = false; 58 | 59 | for(int i=1;i<=n;i++){ 60 | for(int j=1;j<=sum;j++){ 61 | 62 | //Does the current element's value exceed the remaining sum? ==> Current element has to be EXCLUDED 63 | if(A[i-1] > j) T[i][j] = T[i-1][j]; 64 | 65 | //Explore both - Include and Exclude 66 | else T[i][j] = (T[i-1][j] || T[i-1][j-A[i-1]]); 67 | } 68 | } 69 | 70 | return T[n][sum]; 71 | } 72 | 73 | /* 74 | Time Complexity - O(n*sum) 75 | */ 76 | 77 | //RECURSION USING MEMOIZATION - TOP-DOWN APPROACH 78 | 79 | public boolean isSubset(int A[], int current, int sum, HashMap map){ 80 | if(sum==0) return true; 81 | 82 | else if(n==0 && sum!=0) return false; 83 | 84 | String key = current+"|"+sum; 85 | boolean include = false; 86 | boolean exclude = false; 87 | if(!map.containsKey(key)){ 88 | if( A[current-1] > sum ) include = isSubset(A, current-1, sum-A[current-1], map); 89 | exlude = isSubset(A, current-1, sum, map); 90 | map.put(key, (include || exclude)); 91 | } 92 | return map.get(key); 93 | } 94 | 95 | /* 96 | Time and Space Complexity - O(n*sum) 97 | */ 98 | 99 | -------------------------------------------------------------------------------- /DynamicProgramming/SumOfElementsInASubMatrixConstantTime/SumOfAllElementsInASubMatrixInConstantTime.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/calculate-sum-elements-sub-matrix-constant-time/ 3 | 4 | We pre-process and maintain a separate matrix to return answers in constant time. 5 | sum[i][j] represents the sum of all elements in the sub-matrix with top left corner at (0,0) and bottom right corner at (i,j) 6 | Formula - 7 | sum[i][j] = A[i][j] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1] 8 | 9 | Solution to the query - 10 | let (p,q) --> top left corner 11 | and (r,s) --> bottom right corner 12 | 13 | result = sum[r][s] - sum[r][q-1] - sum[p-1][s] + sum[p-1][q-1] 14 | */ 15 | 16 | class SubMatrix{ 17 | int sum[][]; 18 | 19 | public void fillSumMatrix(int A[][]){ 20 | int n = A.length; 21 | int m = A[0].length; 22 | 23 | sum = new int[n][m]; 24 | 25 | sum[0][0] = A[0][0]; 26 | 27 | //pre-process first row 28 | for(int j=1 ; j < m ; j++){ 29 | sum[0][j] = sum[0][j-1] + A[0][j]; 30 | } 31 | 32 | //pre-process first col 33 | for(int i=1 ; i < n ; i++){ 34 | sum[i][0] = sum[i-1][0] + A[i][0]; 35 | } 36 | 37 | //compute rest of the sum-matrix 38 | for(int i=1 ; i < n ; i++){ 39 | for(int j=1 ; j < m ; j++){ 40 | sum[i][j] = A[i][j] + sum[i-1][j] + sum[i][j-1] - sum[i-1][j-1]; 41 | } 42 | } 43 | } 44 | 45 | public int computeQueries(int p, int q, int r, int s){ 46 | //(p,q) --> top left and (r,s) --> bottom right 47 | 48 | int result = sum[r][s]; 49 | 50 | if(q-1 >= 0){ 51 | result -= sum[r][q-1] 52 | } 53 | if(p-1 >= 0){ 54 | result -= sum[p-1][s]; 55 | } 56 | if(q-1 >= 0 && p-1 >= 0){ 57 | result += sum[p-1][q-1]; 58 | } 59 | 60 | return result; 61 | 62 | } 63 | 64 | } 65 | 66 | -------------------------------------------------------------------------------- /DynamicProgramming/WordBreakProblem/WordBreakPrintWords.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://www.techiedelight.com/word-break-problem/ 3 | https://www.geeksforgeeks.org/word-break-problem-using-backtracking/?ref=rp 4 | */ 5 | 6 | public void printWordBreak(String s, Set dict, String res){ 7 | if(s.length() == 0){ 8 | System.out.println(res); 9 | return; 10 | } 11 | 12 | for(int i=1;i<=s.length();i++){ 13 | String prefix = s.substring(0,i); 14 | 15 | if(dict.contains(prefix)){ 16 | printWordBreak(s.substring(i), dict, res+" "+prefix); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /DynamicProgramming/WordBreakProblem/[Optimized]WordBreakPrintWords.java: -------------------------------------------------------------------------------- 1 | /* 2 | https://leetcode.com/problems/word-break-ii/submissions/ 3 | */ 4 | 5 | class Solution { 6 | public List wordBreak(String s, List wordDict) { 7 | if(s.length()==0 || s==null) return new ArrayList(); 8 | 9 | int maxLen = -1; 10 | //to find the length of the longest word in the dictionary 11 | //will be used to minimize iterations 12 | for(int i=0 ; i < wordDict.size() ; i++){ 13 | if(maxLen < wordDict.get(i).length()) maxLen = wordDict.get(i).length(); 14 | } 15 | 16 | //Converting List to Set as retieval from set takes place in constant time 17 | Set dic = new HashSet(wordDict); 18 | 19 | //to store solutions to already seen subproblems 20 | HashMap> map = new HashMap<>(); 21 | 22 | //helper function 23 | return dfs(s,0,maxLen,dic,map); 24 | 25 | } 26 | 27 | public List dfs(String s, int start, int maxLen, Set dict, HashMap> map){ 28 | 29 | //if subproblem is already solved return the stored solution 30 | if(map.containsKey(start)) return map.get(start); 31 | 32 | //list to store solutions to the current subproblem 33 | ArrayList res = new ArrayList(); 34 | 35 | //if we have exhausted the entire string 36 | if(start == s.length()) res.add(""); 37 | 38 | /* 39 | the current subproblem starts at the index 'start' 40 | instead of considering the string s[start..... s.length()-1] 41 | we consider the string ending at minimum of(s.length(), start+maxLen) 42 | Logic - If want to check if current prefix s[start...end] is a word in the dictionary or not - If it is a valid word 43 | it can have a ( maximum length <= length of the longest word in the dictionary ) - considering lengths larger than 44 | this value is simply a waste of iterations, as no such word exisists in the dictionary. 45 | However, there might be a case when we are near the end of the string and [start+maxLen > s.length()] in such case 46 | the upper bound becomes s.length() ==> we take minimum of the two ==> Math.min(s.length(), start+maxLen) 47 | */ 48 | 49 | //considers all possible prefixes 50 | for(int end=start ; end < Math.min(s.length(), start+maxLen) ; end++){ 51 | 52 | String prefix = s.substring(start, end+1); 53 | 54 | //check if the prefix is a valid word 55 | if(dict.contains(prefix)){ 56 | 57 | //solve the subproblem - break down the suffix 58 | //broken suffix is returned - possible to break into multiple valid results - hence a list is returned 59 | List brokenSuffix = dfs(s,end+1,maxLen,dict,map); 60 | 61 | //for each valid broken suffix add the current prefix and store it in the result 62 | for(String suff : brokenSuffix){ 63 | if(suff.length()==0) res.add(prefix); //current prefix is actually the last valid suffix 64 | else res.add(prefix + " " + suff); 65 | } 66 | } 67 | } 68 | 69 | //store result to current subproblem 70 | map.put(start, res); 71 | 72 | //return result to current subproblem 73 | return res; 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Google-Code-Jam-QualificationRound-2020/NestingDepth.java: -------------------------------------------------------------------------------- 1 | /* 2 | Problem Link - https://codingcompetitions.withgoogle.com/codejam/round/000000000019fd27/0000000000209a9f 3 | */ 4 | 5 | import java.util.*; 6 | 7 | class Solution{ 8 | public static void main(String args[]){ 9 | Scanner s = new Scanner(System.in); 10 | int t = s.nextInt(); 11 | for(int i=0;i pN){ 22 | for(int k=0;k<(cN-pN);k++){ 23 | sb.append("("); 24 | } 25 | sb.append(str.charAt(j)); 26 | } 27 | else if(cN < pN){ 28 | for(int k=0;k<(pN-cN);k++){ 29 | sb.append(")"); 30 | } 31 | sb.append(str.charAt(j)); 32 | } 33 | else if(cN == 0 || pN == cN) sb.append(str.charAt(j)); 34 | 35 | pN = cN; 36 | } 37 | 38 | pN = str.charAt(str.length()-1) - '0'; 39 | for(int j=0;j{ 8 | int start; 9 | int end; 10 | time(int s, int e){ 11 | start = s; 12 | end = e; 13 | } 14 | 15 | public int compareTo(time t){ 16 | if(this.start == t.start) return 0; 17 | else if(this.start > t.start) return 1; 18 | else return -1; 19 | } 20 | } 21 | 22 | class Solution{ 23 | public static void main(String args[]){ 24 | Scanner s = new Scanner(System.in); 25 | int t = s.nextInt(); 26 | for(int i=0;i l = new ArrayList