├── Files ├── 01-TwoSum.txt ├── 02-AddTwoNumbers.txt ├── 03-SubstringNoRepeat.txt ├── 04-MedianTwoSortedArrays-Difficult.txt ├── 05-LongestPalindromicSubstring.txt ├── 06-ZigZagConversion.txt ├── 07-ReverseInteger.txt ├── 08-StringtoInteger.txt ├── 09-PalindromeNumber.txt ├── 10-RegularExpressionMatching-Difficult.txt ├── 11-ContainerWithMostWater.txt ├── 12-IntegerToRoman.txt ├── 13-RomanToInteger.txt ├── 14-LongestCommonPrefix.txt ├── 15-3Sum.txt └── 24-SwapNodesinPairs.md └── README.md /Files/01-TwoSum.txt: -------------------------------------------------------------------------------- 1 | //===================================================================================================// 2 | Brute force solution 3 | 4 | public int[] twoSum(int[] nums, int target) { 5 | for (int i=0; i map = new HashMap<>(); 26 | for(int i=0; i 4 -> 3) + (5 -> 6 -> 4) 7 | Output 7 -> 0 -> 8 8 | 9 | 342 + 465 = 807 10 | 11 | //===================================================================================================// 12 | 13 | 14 | Elementary Math Solution 15 | 16 | /** 17 | * Definition for singly-linked list. 18 | * public class ListNode { 19 | * int val; 20 | * ListNode next; 21 | * ListNode(int x) { val = x; } 22 | * } 23 | */ 24 | 25 | 26 | 27 | class Solution { 28 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 29 | ListNode dummyHead= new ListNode(0); 30 | ListNode p=l1, q=l2, curr=dummyHead; 31 | int carry=0; 32 | while (p!=null||q!=null){ 33 | int x= (p!=null) ? p.val :0; //if (p!=null) then x contains p.val 34 | int y= (q!=null) ? q.val :0; 35 | int sum=carry+x+y; 36 | carry=sum/10; 37 | curr.next=new ListNode(sum%10); 38 | curr=curr.next; 39 | if (p!=null) p=p.next; 40 | if (q!=null) q=q.next; 41 | } 42 | if (carry>0){ 43 | curr.next= new ListNode(carry); 44 | } 45 | return dummyHead.next; 46 | } 47 | } 48 | 49 | 50 | Complexity analysis 51 | Time Complexity: O(max(m,n)) depends on the lengths of the two linked lists 52 | Space Complexity: O(max(m,n)) the maximum length of the new list is max(m,n)+1 53 | //===================================================================================================// 54 | -------------------------------------------------------------------------------- /Files/03-SubstringNoRepeat.txt: -------------------------------------------------------------------------------- 1 | //===================================================================================================// 2 | Longest Substring Without Repeating Characters 3 | 4 | Given a string find the length of the longest substring without repeating characters. 5 | 6 | Example 7 | Input: "abcabcbb" 8 | Output: 3 9 | Explanation: The answer is "abc", with the length of 3 10 | 11 | Input: "bbbbb" 12 | Output: 1 13 | Explanation: The answer is "b", with the length of 1 14 | 15 | Input: "pwwkew" 16 | Output: 3 17 | Explanation: The answer is "wke", with the length of 3. Note that the answer must be a substring 18 | "pwke" is a subsequence and not a substring 19 | 20 | 21 | //===================================================================================================// 22 | 23 | Approach 1: Brute Force 24 | Checking all the substrings one by one to see if it has no duplicate character 25 | 26 | Algorithm 27 | 28 | 29 | Suppose we have a function "boolean allUnique(String substring)" which returns true if all the 30 | characters in the substring are unique and false otherwise. We can iterate through all the possible 31 | substrings of the given string s and call the function allUnique. If it turns out to be true, then we 32 | update our answer of the maximum length of substring without duplicate characters. 33 | 34 | To enumerate all substrings of a given string we enumerate the start and end indices of them. Suppose 35 | the start and end indices are i and j respectively. Then we have 0 <= i <= j <= n. Thus using two 36 | nested loops with i from 0 to n-1 and j from i+1 to n, we can enumerate all the substrings of s 37 | 38 | To check if one string has duplicate characters we can use a set. We iterate through all the 39 | characters in the string and put them into the set one by one. Before putting one character, we check 40 | if the set already contains it. If so we return false and after the loop we return true. 41 | 42 | 43 | 44 | 45 | 46 | public class Solution { 47 | public int lengthOfLongestSubstring(String s) { 48 | int n = s.length(); 49 | int ans = 0; 50 | for (int i = 0; i < n; i++) 51 | for (int j = i + 1; j <= n; j++) 52 | if (allUnique(s, i, j)) ans = Math.max(ans, j - i); 53 | return ans; 54 | } 55 | 56 | public boolean allUnique(String s, int start, int end) { 57 | Set set = new HashSet<>(); 58 | for (int i = start; i < end; i++) { 59 | Character ch = s.charAt(i); 60 | if (set.contains(ch)) return false; 61 | set.add(ch); 62 | } 63 | return true; 64 | } 65 | } 66 | 67 | 68 | Complexity Analysis 69 | 70 | Time Complexity: O(n^3) Verifying if characters in [i,j) are unique requires us to scan all of 71 | them which would cost O(j-i) time. 72 | 73 | For a given i, the sum of time costed by each j -> [i+1,n] is 74 | "Summation from i+1 to n O(j-1)" 75 | 76 | Thus, the sum of all the time consumption is: 77 | O(summation from 0 to n-1(summation from j=i+1 to n (j-1))) 78 | O(summation from i=0 to n-1(1+n-i)(n-i)/2)) = O(n^3) 79 | 80 | 81 | *Note that the sum of all numbers up to n 1+2+3+...+n = n(n+1)/2 82 | 83 | 84 | Space Complexity: O(min(n,m)) We require O(k) space for checking a substring has no duplicate 85 | characters, where k is the size of the set. The size of the Set is 86 | upper bounded by the size of the string n amd the size of the charset 87 | or alphabet m 88 | 89 | 90 | 91 | 92 | //===================================================================================================// 93 | 94 | Approach 2: Sliding Window 95 | 96 | 97 | 98 | 99 | A sliding window is an abstract concept commonly used in array/string problems. A window is a range of 100 | elements in the array/string which usually defined by the start and end indices 101 | 102 | ex. [i,j) left-closed, right-open 103 | 104 | A sliding window is a window that slides its two boundaries in a certain direction, for example if we 105 | slide [i,j) to the right by 1 element, then it becomes [i+1, j+1) - left closed, right open. 106 | 107 | 108 | 109 | Sliding Window approach, whenever we are looking at a section on an array usual to perform calculations 110 | we don't need to completely recalculate everything for every section of the array. Usually we can use 111 | the value obtained from another section of the array to determine something about this section of the 112 | array. For example if we are calculating the sum of sections of an array we can use the previously 113 | calculated value of a section to determine the sum of an adjacent section in the array. 114 | 115 | Ex 1 2 3 4 5 6 7 8 116 | 117 | If we calculate the first section of four values we get 1+2+3+4= 10, then to calculate the next section 118 | 2+3+4+5 we can just take our first section (window_sum) and perform the operation: 119 | 120 | window_sum-first entry + last entry = 10-1+5= 14 121 | 122 | So essentially for the window sliding technique we use what we know about an existing window to 123 | determine properties for another window. 124 | 125 | 126 | 127 | 128 | 129 | Algorithm 130 | 131 | In the brute force approach, we repeatedly check a substring to see if it has duplicate characters but 132 | this is unnecessary. If a substring from index i to j-1 is already checked to have no duplicate 133 | characters we only need to check if s[j] is already in the substring. 134 | 135 | To check if a character is already in the substring we can scan the substring which leads to an O(n^2) 136 | algorithm but we can improve on this runtime using a HashSet as a sliding window to check if a 137 | character exists in the current set O(1). 138 | 139 | We use a HashSet to store the characters in the current window [i,j) and then we slide the index j to 140 | the right, if it is not in the HashSet, we slide j further until s[j] is already in the HashSet. At 141 | this point we found the maximum size of substrings without duplicate characters starting with index i. 142 | If we do this for all i, then we obtain our answer. 143 | 144 | 145 | 146 | 147 | public class Solution { 148 | public int lengthOfLongestSubstring(String s) { 149 | int n = s.length(); 150 | Set set = new HashSet<>(); 151 | int ans = 0, i = 0, j = 0; 152 | while (i < n && j < n) { 153 | // try to extend the range [i, j] 154 | if (!set.contains(s.charAt(j))){ 155 | set.add(s.charAt(j++)); 156 | ans = Math.max(ans, j - i); 157 | } 158 | else { 159 | set.remove(s.charAt(i++)); 160 | } 161 | } 162 | return ans; 163 | } 164 | } 165 | 166 | 167 | 168 | Complexity Analysis 169 | 170 | Time complexity: O(2n)=O(n) Worst case each character will be visited twice by i and j 171 | 172 | Space complexity: O(min(m,n)) Same as the brute force method, we need O(k) space for the 173 | sliding window where k is the size of the set. The size of the 174 | set is bounded by the size of the string n and the size of the 175 | charset/alphabet m 176 | 177 | 178 | 179 | 180 | 181 | //===================================================================================================// 182 | 183 | Approach 3: Sliding Window Optimized 184 | 185 | The previously discussed sliding window approach requires at most 2n steps and this could in fact be 186 | optimized even further to require only n steps. Instead of using a set to tell if a character exists or 187 | not, we could define a mapping of the characters to its index. Then we can skip the characters 188 | immediately when we found a repeated character 189 | 190 | If s[j] has a duplicate in the range [i,j) with index j', we don't need to increase i little be little 191 | we can just skip all the elements in the range [i,j'] and let i be j'+1 directly 192 | 193 | 194 | *** 195 | 196 | 197 | public class Solution { 198 | public int lengthOfLongestSubstring(String s) { 199 | int n = s.length(), ans = 0; 200 | Map map = new HashMap<>(); // current index of character 201 | // try to extend the range [i, j] 202 | for (int j = 0, i = 0; j < n; j++) { 203 | if (map.containsKey(s.charAt(j))) { 204 | i = Math.max(map.get(s.charAt(j)), i); 205 | } 206 | ans = Math.max(ans, j - i + 1); 207 | map.put(s.charAt(j), j + 1); 208 | } 209 | return ans; 210 | } 211 | } 212 | 213 | 214 | 215 | //===================================================================================================// 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | -------------------------------------------------------------------------------- /Files/04-MedianTwoSortedArrays-Difficult.txt: -------------------------------------------------------------------------------- 1 | //===================================================================================================// 2 | Median of Two Sorted Arrays 3 | 4 | There are two sorted arrays num1 and num2 of size m and n respectively. Find the median of the two 5 | sorted arrays. The overall run time complexity should be O(log (m+n)). You may assume nums1 and nums2 6 | cannot be both empty. 7 | 8 | Example 9 | 10 | nums1 = [1, 3] 11 | nums2 = [2] 12 | 13 | The median is 2.0 14 | 15 | Example 2 16 | 17 | nums1= [1, 2] 18 | nums2= [3, 4] 19 | 20 | The median is (2+3)/2 = 2.5 21 | 22 | 23 | Approach: Recursive Approach 24 | 25 | In statistics the median is used for dividing a set into two equal length subsets with one set being 26 | always greater than the other set. To approach this problem first we cut A into two parts at a random 27 | position i: 28 | 29 | 30 | left_A | right_A 31 | 32 | A[0], A[1], ... , A[i-1] A[i], A[i+1], ... , A[m-1] 33 | 34 | 35 | Since A has m elements, there are m+1 kinds of cutting as i can range from 0-m. We can also see that 36 | left_A is empty when i is zero and right_A is empty when i=m 37 | 38 | len(left_A) = i and len(right_A)= m-i 39 | 40 | 41 | We can similarly cut B into two parts at a random position j: 42 | 43 | 44 | left_B | right_B 45 | 46 | B[0], B[1], ... , B[j-1] B[j], B[j+1], ... , B[n-1] 47 | 48 | 49 | 50 | Now if we put left_A and left_B into one set and put right_A and right_B into another set and name 51 | them left_part and right_part, then we get 52 | 53 | 54 | left_part | right_part 55 | A[0], A[1], ... , A[i-1] A[i], A[i+1], ... , A[m-1] 56 | B[0], B[1], ... , B[j-1] B[j], B[j+1], ... , B[n-1] 57 | 58 | 59 | If we can ensure that 60 | 1) the len(left_part) = len(right_part) 61 | 2) max(left_part) <= min(right_part) 62 | 63 | then we divide all the elements in {A,B} into two parts with equal length and one part is always 64 | greater than the other. Then 65 | 66 | median= (max(left_part)+min(right_part))/2 67 | 68 | To ensure these two conditions, we need to ensure: 69 | 1) i+j= m-i+n-j (or: m-i+n-j+1) if n>m, we just need to set i=0~m, j= (m+n+1)/2 - i 70 | 2) B[j-1]<=A[i] and A[i-1]<=B[j] 71 | 72 | So, all we need to do is search for i in [0,m] to find an object i such that 73 | B[j-1]<=A[i] and A[i-1]<=B[j] where j=(m+n+1)/2 -i 74 | 75 | Then we perform a binary search following the steps described below: 76 | 77 | 1) Set imin=0, imax=0, then start searching in [imin, imax] 78 | 2) Set i=(imin+imax)/2 , j=(m+n+1)/2 - i 79 | 3) Now we have len(left_part) = len(right_part) and there are only 3 more situations which we may 80 | encounter: 81 | 82 | - B[j-1] <= A[i] and A[i-1]<=B[j] 83 | This means that we have found the object i, so we can stop searching 84 | 85 | - B[j-1] > A[i] 86 | Means A[i] is too small, we must adjust i to get B[j-1]<=A[i] so we increase i because this will 87 | cuase j to be decreased. We cannot decrease i because when i is decreased, j will be increased 88 | so B[j-1] is increased and A[i] is decreased (B[j-1]<= A[i] will never be satisfied) 89 | 90 | - A[i-1] > B[j] 91 | Means A[i-1] is too big and thus we must decrease i to get A[i-1]<=B[j]. In order to do that we 92 | must adjust the searching range to [imin, i-1] so we set imax=i-1 and go back to step 2 93 | 94 | When the object i is found, then the media is: 95 | 96 | max(A[i-1],B[j-1]), when m+n is odd 97 | (max(A[i-1],B[j-1])+min(A[i],B[j]))/2, when m+n is even 98 | 99 | Next is to consider the edge values i=0, i=m, j=0, j=n where A[i-1], B[j-1], A[i], B[j] may not exist 100 | 101 | 102 | class Solution { 103 | public double findMedianSortedArrays(int[] A, int[] B) { 104 | int m=A.length; 105 | int n=B.length; 106 | if (m>n) { //ensuring that m<=n 107 | int[] temp=A; A=B; B=temp; 108 | int tmp=m; m=n; n=tmp; 109 | } 110 | int iMin=0, iMax=m, halfLen=(m+n+1)/2; 111 | while (iMin<=iMax) { 112 | int i=(iMin+iMax)/2 113 | int j= halfLen - i; 114 | if (i A[i]){ 115 | iMin=i+1; //i is too small 116 | } 117 | else if (i>iMin && A[i-1]>B[j]) { 118 | iMax=i-1; //i is too big 119 | } 120 | else{ //we have found the object i 121 | int maxLeft=0; 122 | if (i==0) { 123 | maxLeft=B[j-1]; 124 | } 125 | else if (j==0){ 126 | maxLeft=A[i-1]; 127 | } 128 | else{ 129 | maxLeft=Math.max(A[i-1], B[j-1]); 130 | } 131 | 132 | if ((m+n)%2 ==1) { 133 | return maxLeft; 134 | } 135 | 136 | int minRIght=0; 137 | if (i==m) { 138 | minRight=B[j]; 139 | } 140 | else if (j==n) { 141 | minRight=A[i]; 142 | } 143 | else { 144 | minRight=Math.min(B[j], A[i]); 145 | } 146 | 147 | return (maxLeft+minRight)/2.0; 148 | } 149 | } 150 | return 0.0; 151 | } 152 | } 153 | 154 | 155 | Time Complexity: O(log(min(m,n))) At first the searching range is [0,m] and the length of this 156 | searching range will be reduced by half after each loop so we 157 | only need log(m) loops. Since we do constant operations in 158 | each loop the time complexity is O(log(m) and since m<=n the 159 | time complexity is O(log(min(m,n)) 160 | 161 | Space Complexity: O(1) We only need constant memory to store 9 local variables so the 162 | space complexity is O(1) 163 | 164 | //===================================================================================================// 165 | 166 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /Files/05-LongestPalindromicSubstring.txt: -------------------------------------------------------------------------------- 1 | //===================================================================================================// 2 | //Longest Palindromic Substring 3 | 4 | Given a string s, find the longest palindromic substring in s. You may assume that the maximum length 5 | of s is 1000. 6 | 7 | Example 1: 8 | 9 | Input: "babad" 10 | Output: "bab" 11 | 12 | Note: "aba" is also a valid answer 13 | 14 | Example 2: 15 | 16 | Input: "cbbd" 17 | Output: "bb" 18 | 19 | //===================================================================================================// 20 | 21 | Approach 1: Longest Common Substring 22 | 23 | Some people will be tempted to come up with this quick solution which is unforunately flawed, "reverse 24 | S and become S'. Find the longest common substring between S and S' and that will be the longest 25 | palindromic substring." This will work with some examples but there are some cases where the longest 26 | common substring is not a valid palindrome. 27 | 28 | Ex. S="abacdfgdcaba", S'="abacdgfdcaba" 29 | 30 | The longest common substring between S and S' is "abacd" and clearly this is not a valid 31 | palindrome 32 | 33 | We can solve this problem however by checking if the substring's indices are the same as the reversed 34 | substring's original indices each time we find a longest common substring. If it is, then we attempt 35 | to update the longest palindrome found so far, if not we skip this and find the next candidate 36 | 37 | Time Complexity: O(n^2) 38 | Space Complexity: O(n^2) 39 | 40 | //==================================================================================================// 41 | 42 | Approach 2: Brute Force 43 | 44 | The obvious brute force solution is to pick all possible starting and ending position for a substring 45 | and verify if it is a palindrome 46 | 47 | Time Complexity: O(n^3) If n is the length of the input string, there are a total of 48 | (n 2) = n(n-1)/2 substrings and since verifying each substring takes 49 | O(n) time, the run time complexity is O(n^3) 50 | 51 | Space Complexity: O(1) 52 | 53 | 54 | //===================================================================================================// 55 | 56 | Approach 3: Dynamic Programming 57 | 58 | We can improve on the brute force solution by avoid some unnecessary re-computation while validating 59 | palidromes. Consider the word "ababa", if we already know that "bab" is a palindrome then we can 60 | determine that ababa is a palindrome by noticing that the two left and right letters connected to bab 61 | are the same. 62 | 63 | This yields a straight forward dynamic programming solution where we initialize the one and two letters 64 | palindromes and then work our way up finding all three letters palindromes and so on. 65 | 66 | 67 | Time Complexity: O(n^2) 68 | 69 | Space Complexity: O(n^2) Using O(n^2) space to store the table 70 | 71 | 72 | //===================================================================================================// 73 | 74 | Approach 4: Expand Around Center 75 | 76 | This approach allows us to solve this problem in O(n^2) time using only constant space complexity. We 77 | observe that a palindrome mirrors around its enter and therefore a palindrome can be expanded from its 78 | center and there are only 2n-1 such centers (for palindromes with an even number of letters like 79 | "abba" its center is in between two letters). 80 | 81 | 82 | 83 | public String longestPalindrome(String s) { 84 | if (s==null || s.length() < 1) return ""; //edge case 85 | int start=0, end=0; 86 | for (int i=0; iend-start) { 91 | start= i-(len-1)/2; 92 | end=i+len/2 93 | } 94 | } 95 | return s.substring(start,end+1); 96 | } 97 | 98 | private int expandAroundCenter(String s, int left, int right) { 99 | int L=left, R=right; 100 | while(L>=0 && R rows=new ArrayList<>(); 54 | for (int i=0; i=INTMAX/10 52 | 2) If rev> INTMAX/10, then temp=rev*10+pop is guaranteed to overflow 53 | 3) if rev==INTMAX/10, then temp=rev*10 + pop will overflow if an only if pop>7 54 | 55 | 56 | class Solution { 57 | public int reverse(int x) { 58 | int rev=0; 59 | while (x!=0) { 60 | int pop=x%10; 61 | x/=10; 62 | if (rev>Integer.MAX_VALUE/10||(rev==Integer.MAX_VALUE/10 && pop>7)) return 0; 63 | if (rev 1 72 | 49 - 48 => 1 73 | 74 | 75 | public int myAtoi(String str) { 76 | int index=0, sign=1, total=0; 77 | 78 | //1. Empty string 79 | if (str.length() ==0) return 0; 80 | 81 | //2. Remove Spaces 82 | while(str.charAt(index)==' ' && index < str.length()) 83 | index++; 84 | 85 | //3. Handle signs 86 | if (str.charAt(index)=='+' || str.charAt(index)=='-'){ 87 | sign= str.charAt(index) == '+' ? 1:-1; 88 | index++; 89 | } 90 | 91 | //4. COnvert number and avoid overflow 92 | while(index9) break; 95 | 96 | //check if total will overflow after 10 times and add digit 97 | if (Integer.MAX_VALUE/10 < total || Integer.MAX_VALUE/10 == total 98 | && Integer.MAX_VALUE%10revertedNumber){ 78 | revertedNumber=x%10+revertedNumber*10; 79 | x/=10; 80 | } 81 | //when the length is an odd number, we can get rid of the middle digit by 82 | //revertedNumber/10 83 | 84 | //For example when the input is 12321, at the end of the while loop we get x=12, 85 | //revertedNumber=123, since the middle digit doesn't matter in a palindrome we can 86 | //simply get rid of it 87 | 88 | return x==revertedNumber||x==revertedNumber/10; 89 | } 90 | } 91 | 92 | 93 | //===================================================================================================// 94 | -------------------------------------------------------------------------------- /Files/10-RegularExpressionMatching-Difficult.txt: -------------------------------------------------------------------------------- 1 | //===================================================================================================// 2 | //Regular Expression Matching 3 | 4 | Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' 5 | and '*' 6 | 7 | '.' Matches any single character 8 | '*' Matches zero or more of the preceding element 9 | 10 | The matching should cover the entire input string (not partial) 11 | 12 | Note: 13 | 14 | - s could be empty and contains only lower case letters a-z 15 | - p could be empty and contains only lower case letters a-z and characters like . or * 16 | 17 | 18 | Example 1: 19 | 20 | Input: 21 | s="aa" 22 | p="a" 23 | Output: false 24 | Explanation: "a" does not match the entire string "aa" 25 | 26 | 27 | 28 | Example 2: 29 | 30 | Input: 31 | s="aa" 32 | p="a*" 33 | Output: true 34 | Explanation: '*' means zero of more of the preceding element, 'a'. Therefore, by repeating 35 | 'a' once it becomes "aa" 36 | 37 | 38 | Example 3: 39 | 40 | Input: 41 | s="ab" 42 | p=".*" 43 | Output: true 44 | Explanation: '.*' means "zero or more (*) of any character (.)" 45 | 46 | 47 | Example 4: 48 | 49 | Input: 50 | s="aab" 51 | p="c*a*b" 52 | Output: true 53 | Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches 54 | "aab" 55 | 56 | 57 | Example 5: 58 | 59 | Input: 60 | s="mississippi" 61 | p="mis*is*p*." 62 | Output: false 63 | 64 | 65 | //===================================================================================================// 66 | 67 | Approach 1: Recursion 68 | 69 | If there were no Kleene stars (the * wildcard characters for regular expressions), the problem would 70 | be easier- we simply check from left to right if each character of the text matches the pattern. When 71 | a star is present we may need to check for may different suffixes of the text and see if they match 72 | the rest of the pattern. A recursive solution is a straightforward way to represent this relationship 73 | 74 | 75 | class Solution { 76 | public boolean isMatch(String text, String pattern) { 77 | if (pattern.isEmpty()) return text.isEmpty(); 78 | 79 | boolean first_match=(!text.isEmpty() && 80 | (pattern.charAt(0)==text.charAt(0) || pattern.charAt(0)=='.')); 81 | 82 | if (pattern.length()>=2 && pattern.charAt(1) =='*'){ 83 | return (isMatch(text,pattern.substring(2))|| 84 | (first_match && isMatch(text.substring(1),pattern))); 85 | 86 | //note: pattern.substring(2) returns all of the characters after index 2 of pattern 87 | } 88 | else { 89 | return first_match && isMatch(text.substring(1), pattern.substring(1)); 90 | } 91 | 92 | } 93 | } 94 | 95 | 96 | Complexity Analysis 97 | 98 | Time Complexity: Let T, P be the lengths of the text and the pattern respectively. In the worst 99 | case, a call to match(text[i:],pattern[2j:]) will be made (i+j i) times, and 100 | strings of the order O(T-i) and O(P-2*j) will be made. Thus the complexity has 101 | the order: 102 | 103 | summation from i=0 to T * summation from j=0 to P/2 * (i+j i) O(T+P-i-2j). 104 | 105 | We can show that this is bounded by O((T+P)2^(T+P/2)) 106 | 107 | Space Complexity: For every call to match, we will create those strings as described above 108 | possibly creating duplicates. If memory is not freed, this will also take a 109 | total of O((T+P)2^(T+P/2)) space even though there are only order O(T^2+P^2) 110 | unique suffixes of P and T that are actually required 111 | 112 | 113 | 114 | //===================================================================================================// 115 | 116 | Approach 2: Dynamic Programming 117 | 118 | As the problem has an optimal substructure, it is natural to cache intermediate results. We ask the 119 | question dp(i,j): does text[i:] and pattern[j:] match? We can describe our answer in terms of answers 120 | to questions involving smaller strings 121 | 122 | Algorithm 123 | 124 | We proceed with the same recursion as in Approach 1, except because calls will only ever be made to 125 | match(text[i:], pattern[j:]), we use dp(i,j) to handle those calls instead, saving us expensive 126 | string-building operations and allowing us to cache the intermediate results 127 | 128 | 129 | Java Top-Down Variation 130 | 131 | 132 | 133 | enum Result { 134 | TRUE, FALSE 135 | 136 | } 137 | 138 | class Solution { 139 | Result[][] memo; 140 | 141 | public boolean isMatch(String text, String pattern) { 142 | memo=new Result[text.length() +1][pattern.length() +1]; 143 | return dp(0,0,text,pattern); 144 | } 145 | 146 | public boolean dp(int i, int j, String text, String pattern) { 147 | if (memo[i][j]!=null) { 148 | return memo[i][j]==Result.TRUE; 149 | } 150 | boolean ans; 151 | if (j==pattern.length()){ 152 | ans=i==text.length(); 153 | } 154 | else { 155 | boolean first_match=(i map = new HashMap(); 73 | map.put('I', 1); 74 | map.put('V', 5); 75 | map.put('X', 10); 76 | map.put('L', 50); 77 | map.put('C', 100); 78 | map.put('D', 500); 79 | map.put('M', 1000); 80 | 81 | char[] sc= s.toCharArray(); 82 | int total= map.get(sc[0]); 83 | int pre=map.get(sc[0]); 84 | for (int i=1; ii, S[1...j] is not a common 254 | string and we discard the second half of the search space 255 | 256 | - S[1...mid] is common string. This means that for each i
359 | *Algorithm* 360 | 361 | The only question left is how to find the deepest path in the Trie, that fulfills the requirements 362 | above. The most effective way is to build a trie from {S1 ... Sn] strings. Then find the prefix of 363 | query string q in the Trie. We traverse the Trie from the root, till it is impossible to continue the 364 | path in the Trie because one of the conditions above is not satisfied. 365 | 366 | 367 | ``` 368 | Searching for the longest common prefix of string "le" in a Trie from dataset {lead, leet} 369 | 370 | Root 371 | 372 | 1 373 | 374 | l ===========> \ l 375 | 376 | 2 377 | 378 | e ===============> \ e 379 | 380 | LCP "le" FOUND =============> 3 381 | 382 | a / \ e End of Key "lee" 383 | 384 | 6 4 385 | 386 | d / \ t 387 | 388 | END OF KEY "lead" 7 5 End of key "leet" 389 | ``` 390 | 391 | 392 | 393 | ``` 394 | public String longestCommonPrefix(String q, String[] strs) { 395 | if (strs == null || strs.length == 0) 396 | return ""; 397 | if (strs.length == 1) 398 | return strs[0]; 399 | Trie trie = new Trie(); 400 | for (int i = 1; i < strs.length ; i++) { 401 | trie.insert(strs[i]); 402 | } 403 | return trie.searchLongestPrefix(q); 404 | } 405 | 406 | class TrieNode { 407 | 408 | // R links to node children 409 | private TrieNode[] links; 410 | 411 | private final int R = 26; 412 | 413 | private boolean isEnd; 414 | 415 | // number of children non null links 416 | private int size; 417 | public void put(char ch, TrieNode node) { 418 | links[ch -'a'] = node; 419 | size++; 420 | } 421 | 422 | public int getLinks() { 423 | return size; 424 | } 425 | //assume methods containsKey, isEnd, get, put are implemented as it is described 426 | //in https://leetcode.com/articles/implement-trie-prefix-tree/) 427 | } 428 | 429 | public class Trie { 430 | 431 | private TrieNode root; 432 | 433 | public Trie() { 434 | root = new TrieNode(); 435 | } 436 | 437 | //assume methods insert, search, searchPrefix are implemented 438 | private String searchLongestPrefix(String word) { 439 | TrieNode node = root; 440 | StringBuilder prefix = new StringBuilder(); 441 | for (int i = 0; i < word.length(); i++) { 442 | char curLetter = word.charAt(i); 443 | if (node.containsKey(curLetter) && (node.getLinks() == 1) && (!node.isEnd())) { 444 | prefix.append(curLetter); 445 | node = node.get(curLetter); 446 | } 447 | else 448 | return prefix.toString(); 449 | 450 | } 451 | return prefix.toString(); 452 | } 453 | } 454 | ``` 455 | 456 | **Complexity Analysis** 457 | ``` 458 | In the worst case query q has length m and is equal to all n strings of the array 459 | 460 | Time Complexity: O(S) where S is the number of all characters in the array, LCP query O(m) 461 | Trie build has O(S) time complexity. To find the common prefix of q in the Trie takes 462 | in the worst O(m). 463 | Space complexity: O(S) we only used additional S extra space for the Trie. 464 | ``` 465 | 466 | //===================================================================================================// 467 | 468 | Trie (pronounced Try - Prefix tree) and the most common Operations With It 469 | 470 | 471 | Implement a trie with insert, search, and startsWith methods 472 | 473 | Example: 474 | Trie trie=new Trie(); 475 | 476 | trie.insert("apple"); 477 | trie.search("apple"); //returns true 478 | trie.search("app"); //returns false 479 | trie.startsWith("app"); //returns true 480 | trie.insert("app"); 481 | trie.search("app"); //returns true 482 | 483 | Note 484 | 485 | * You may assume that all inputs consist of lowercase letters a-z 486 | * All inputs are guaranteed to be non-empty strings 487 | 488 | 489 |

490 | ## Solution 491 | 492 | Trie (we pronounce "try") or prefix tree is a tree data structure which is used for the retrieval of a 493 | key in a dataset of strings. THere are various applications of this very efficient data structure such 494 | as: 495 | 496 | * Autocomplete 497 | * Spell checker 498 | * IP routing (Longest prefix matching) 499 | * T9 predictive text (text on nine keys - used on phones during the late 1990s) 500 | * Solving word games 501 | 502 | 503 | There are several other data structures like balanced trees and hash tables which give us the 504 | possibility to search for a word in a dataset of strings so why do we use a trie? Althought a hash 505 | table has O(1) time complexity for looking for a key, it is not efficient in the following operations: 506 | 507 | * Finding all keys with a common prefix 508 | * Enumerating a dataset of strings in lexicographical order 509 | 510 | Another reason why the trie outperforms has table, is that as hash table increases in size, there are 511 | lots of hash collisions and the search time complexity could deteriorate to O(n), where n is the 512 | number of keys inserted. Tries could use less space compared to Hash Table when storing many keys with 513 | the same prefix. In this case using trie has only O(m) time complexity, where m is the key length. 514 | Searching for a key in balanced tree costs O(m log n) time complexity. 515 | 516 | 517 | ## Trie node structure 518 | 519 | Trie is a rooted tree. Its nodes have the following fields: 520 | 521 | * Maximum of R links to its children, where each link corresponds to one of R character values from 522 | dataset alphabet. In this article we assume that R is 26, the number of lowercase latin letters 523 | 524 | * Boolean field which specifies whether the node corresponds to the end of the key, or is just a 525 | key prefix 526 | 527 | 528 | ``` 529 | 530 | Root 531 | 532 | isEnd: false 533 | a b c d e f g h i j k l m n o p q r s t u v w x y z 534 | 535 | | 536 | 537 | link 538 | 539 | isEnd: false 540 | a b c d e f g h i j k l m n o p q r s t u v w x y z 541 | 542 | | 543 | 544 | link 545 | 546 | isEnd: false 547 | a b c d e f g h i j k l m n o p q r s t u v w x y z 548 | 549 | | 550 | 551 | link 552 | 553 | isEnd: false 554 | a b c d e f g h i j k l m n o p q r s t u v w x y z 555 | 556 | | 557 | 558 | link 559 | 560 | isEnd: true 561 | 562 | 563 | Representation of a key "leet" in trie 564 | ``` 565 | 566 | ```java 567 | class TrieNode { 568 | 569 | // R links to node children 570 | private TrieNode[] links; 571 | 572 | private final int R = 26; 573 | 574 | private boolean isEnd; 575 | 576 | public TrieNode() { 577 | links = new TrieNode[R]; 578 | } 579 | 580 | public boolean containsKey(char ch) { 581 | return links[ch -'a'] != null; 582 | } 583 | public TrieNode get(char ch) { 584 | return links[ch -'a']; 585 | } 586 | public void put(char ch, TrieNode node) { 587 | links[ch -'a'] = node; 588 | } 589 | public void setEnd() { 590 | isEnd = true; 591 | } 592 | public boolean isEnd() { 593 | return isEnd; 594 | } 595 | } 596 | ``` 597 | 598 | Two of the most common operations in a trie are insertion of a key and search for a key 599 | 600 | 601 | 602 | 603 | ## Insertion of a key to a trie 604 | 605 | We insert a key by searching into the trie. We start from the root and search a link, which corresponds 606 | to the first key character. There are two cases: 607 | 608 | * A link exists. Then we move down the tree following the link to the next child level. The algorithm 609 | continues with searching for the next key character. 610 | 611 | * A link does not exist. Then we create a new node and link it with the parent's link matching the 612 | current key character. We repeat this step until we encounter the last character of the key, then 613 | we mark the current node as an end node and the algorithm finishes. 614 | 615 | 616 | ``` 617 | Inserting "le" into the Trie 618 | 619 | 620 | Root 621 | 622 | 1 623 | 624 | \ l 625 | 626 | 2 627 | 628 | \ e 629 | 630 | 3 End of Key "le" 631 | 632 | 633 | ``` 634 | 635 | ``` 636 | Inserting "leet" into the Trie 637 | 638 | 639 | 640 | 641 | Root 642 | 643 | 1 644 | 645 | \ l 646 | 647 | 2 648 | 649 | \ e 650 | 651 | 3 End of key "le" 652 | 653 | \ e 654 | 655 | 4 656 | 657 | \ t 658 | 659 | 5 End of key "leet" 660 | 661 | ``` 662 | 663 | 664 | ``` 665 | Inserting "code" into the Trie 666 | 667 | 668 | 669 | Root 670 | 671 | 1 672 | 673 | c / \ l 674 | 675 | 6 2 676 | 677 | o / \ e 678 | 679 | 7 3 End of key "le" 680 | 681 | d / \ e 682 | 683 | 8 4 684 | 685 | e / \ t 686 | 687 | End of key "code" 9 5 End of Key "root" 688 | 689 | 690 | ``` 691 | 692 | Building a Trie from dataset {le, leet, code} 693 | 694 | 695 | ```java 696 | class Trie { 697 | private TrieNode root; 698 | 699 | public Trie() { 700 | root = new TrieNode(); 701 | } 702 | 703 | // Inserts a word into the trie. 704 | public void insert(String word) { 705 | TrieNode node = root; 706 | for (int i = 0; i < word.length(); i++) { 707 | char currentChar = word.charAt(i); 708 | if (!node.containsKey(currentChar)) { 709 | node.put(currentChar, new TrieNode()); 710 | } 711 | node = node.get(currentChar); 712 | } 713 | node.setEnd(); 714 | } 715 | } 716 | ``` 717 | 718 | **Complexity Analysis** 719 | 720 | ``` 721 | Time complexity: O(m) where m is the key length. In each iteration of this algorithm we 722 | either create a node in the trie till we reach the end of the key. 723 | This takes only m operations 724 | 725 | Space complexity: O(m) In the worst case newly inserted key doesn't share a prefix with the 726 | keys already inserted in the trie. We have to add m new nodes, which 727 | only takes us O(m) space 728 | ``` 729 | 730 | 731 | ## Search for a Key in a Trie 732 | 733 | 734 | Each key is represented in the trie as a path from the root to the internal node or leaf. We start from 735 | the root with the first key character. We examine the current node for a link corresponding to the key 736 | character. There are two cases: 737 | 738 | * A link exists. We move to the next node in the path following this link, and proceed searching for 739 | the next key character 740 | * A link does not exist. If there are no available key characters and current node is marked as isEnd 741 | we return true. Otherwise there are two possible cases in each of them we return false: 742 | 743 | * There are key characters left, but it is impossible to follow the key path in the trie, and the 744 | key is missing 745 | * No key characters left, but current node is not marked as isEnd. Therefore the search key is only 746 | a prefix of another key in the trie 747 | 748 | 749 | ``` 750 | Searching for key "leet" in the Trie 751 | 752 | Root 753 | 754 | 1 755 | 756 | c / \ l <============================== l 757 | 758 | 6 2 759 | 760 | o / \ e <=========================== e 761 | 762 | 7 3 End of key "le" 763 | 764 | d / \ e <===================== e 765 | 766 | 8 4 767 | 768 | e / \ t <================= t 769 | 770 | End of key "code" 9 5 End of Key "root" <============ Key Found 771 | 772 | 773 | ``` 774 | 775 | ```java 776 | class Trie { 777 | ... 778 | 779 | // search a prefix or whole key in trie and 780 | // returns the node where search ends 781 | private TrieNode searchPrefix(String word) { 782 | TrieNode node = root; 783 | for (int i = 0; i < word.length(); i++) { 784 | char curLetter = word.charAt(i); 785 | if (node.containsKey(curLetter)) { 786 | node = node.get(curLetter); 787 | } else { 788 | return null; 789 | } 790 | } 791 | return node; 792 | } 793 | 794 | // Returns if the word is in the trie. 795 | public boolean search(String word) { 796 | TrieNode node = searchPrefix(word); 797 | return node != null && node.isEnd(); 798 | } 799 | } 800 | ``` 801 | 802 | **Complexity Analysis** 803 | 804 | ``` 805 | Time Complexity: O(m) In each step of the algorithm we search for the next key character. 806 | In the worst case the algorithm performs m operations 807 | Space Complexity: O(1) 808 | ``` 809 | 810 | 811 | ## Search for a key prefix in a trie 812 | 813 | The approach is very similar to the one we used for searching a key in a trie. We traverse the trie 814 | from the root, till there are no character left in key prefix or it is impossible to continue the path 815 | in the trie with the current key character. The only difference with the mentioned above search for a 816 | key algorithm is that when we come to an end of the key prefix, we always return true. We don't need to 817 | conside the isEnd mark of the current trie node, because we are searching for a prefix of a key, not 818 | for a whole key. 819 | 820 | 821 | ``` 822 | Searching for "co" in the Trie 823 | 824 | 825 | Root 826 | 827 | 1 828 | 829 | c ==============> c / \ l 830 | 831 | 6 2 832 | 833 | o ============> o / \ e 834 | 835 | Prefix Found 7 3 End of key "le" 836 | 837 | d / \ e 838 | 839 | 8 4 840 | 841 | e / \ t 842 | 843 | End of key "code" 9 5 End of Key "root" 844 | ``` 845 | 846 | ```java 847 | class Trie { 848 | ... 849 | 850 | // Returns if there is any word in the trie 851 | // that starts with the given prefix. 852 | public boolean startsWith(String prefix) { 853 | TrieNode node = searchPrefix(prefix); 854 | return node != null; 855 | } 856 | } 857 | ``` 858 | 859 | **Complexity Analysis** 860 | ``` 861 | Time Complexity: O(m) 862 | Space Complexity: O(1) 863 | ``` 864 | 865 | //===================================================================================================// 866 | -------------------------------------------------------------------------------- /Files/15-3Sum.txt: -------------------------------------------------------------------------------- 1 | //===================================================================================================// 2 | 3Sum 3 | 4 | Given an array "nums" of n integers, are there elements a, b, c in nums such that a+b+c=0? Find all 5 | unique triplets in the array which gives the sum of zero. 6 | 7 | Note: 8 | 9 | The solution set must not contain duplicate triplets 10 | 11 | ``` 12 | Example: 13 | 14 | Given array nums = [-1, 0, 1, 2, -1, -4]. 15 | 16 | A solution set is: 17 | [ 18 | [-1, 0, 1], 19 | [-1, -1, 2] 20 | ] 21 | ``` 22 | 23 | Sorted Array 24 | 25 | The method is to sort an input array and then run through all indices of a possible first element of a 26 | triplet. For each element we make another 2Sum sweep of the remaining part of the array. Also we want 27 | to skip elements to avoid duplicates in the answer without expending extra memory. 28 | 29 | ``` 30 | public List> threeSum(int[] num) { 31 | 32 | //Arrays.sort re-arranges the array of integers in ascending order 33 | //ex. [1, 2, 3, 4] 34 | 35 | Arrays.sort(num); 36 | List> res = new LinkedList<>(); 37 | for (int i = 0; i < num.length-2; i++) { 38 | if (i == 0 || (i > 0 && num[i] != num[i-1])) { 39 | 40 | //This lets us skip some of the duplicate entries in the array 41 | 42 | int lo = i+1, hi = num.length-1, sum = 0 - num[i]; 43 | 44 | //This is for the 2 Sum sweep 45 | 46 | while (lo < hi) { 47 | if (num[lo] + num[hi] == sum) { 48 | res.add(Arrays.asList(num[i], num[lo], num[hi])); 49 | while (lo < hi && num[lo] == num[lo+1]) lo++; 50 | while (lo < hi && num[hi] == num[hi-1]) hi--; 51 | 52 | //This lets us skip some of the duplicate entries in the array 53 | 54 | lo++; hi--; 55 | } else if (num[lo] + num[hi] < sum) lo++; 56 | else hi--; 57 | 58 | //This allows us to optimize slightly since we know that the array is sorted 59 | } 60 | } 61 | } 62 | return res; 63 | } 64 | ``` 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | //===================================================================================================// 73 | -------------------------------------------------------------------------------- /Files/24-SwapNodesinPairs.md: -------------------------------------------------------------------------------- 1 | ## 24-Swap Nodes in Pairs 2 | 3 | Given a linked list, swap every two adjacent nodes and return its head. 4 | 5 | You may **not** modify the values in the list's nodes, only nodes itself may be changed 6 | 7 | ``` 8 | Example: 9 | 10 | Input: 1 -> 2 -> 3 -> 4 11 | Output: 2 -> 1 -> 4 -> 3 12 | ``` 13 | 14 |

15 | ## Recursion 16 | 17 | ```java 18 | public class Solution { 19 | public ListNode swapPairs(ListNode head) { 20 | 21 | if ((head==null)||(head.next==null)) 22 | return head; 23 | 24 | ListNode n = head.next; 25 | head.next = swapPairs(head.next.next); 26 | n.next = head; 27 | 28 | return n; 29 | } 30 | } 31 | ``` 32 | 33 | 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LeetCode - CheatSheet 2 | 3 | A compilation of notes that I made when working with Leetcode problems - Note a majority of the content and code was taken off of 4 | the solution and discuss sections of the Leetcode website so I do not take any ownership of the below. The following is simply 5 | notes compiled for learning purposes. 6 | 7 | 8 | ## Getting Started 9 | 10 | Currently LeetCode-CheatSheet contains various text files for notes but is primarily composed of this README file which supports 11 | the markdown formatting language. This makes the notes and code look a lot better and supports many awesome features like quick links 12 | and makes formatting much easier. 13 | 14 | 15 | ### Prerequisites 16 | 17 | In the future I might add a html document which also performs some formatting and if that comes out, ideally the html and css 18 | would be written for web browsers on large screens which support the newest version of bootstrap and html 5. 19 | I use the following application when building and testing html. 20 | 21 | ``` 22 | Chrome Version 71.0.3578.98 23 | ``` 24 | 25 | 26 | ## Built With 27 | 28 | * [Markdown](https://guides.github.com/features/mastering-markdown/) - Syntax styling 29 | 30 | 31 | 32 | ## Authors 33 | 34 | * **Lichen Ma** - *compiling information* 35 | 36 | 37 | 38 | ## Acknowledgments 39 | 40 | * **Leetcode** - *content belongs to respective creators* 41 | 42 | 43 | ## Quick Access Links 44 | ### LeetCode 45 | - [LeetCode - CheatSheet](#leetcode---cheatsheet) 46 | - [Getting Started](#getting-started) 47 | - [Prerequisites](#prerequisites) 48 | - [Built With](#built-with) 49 | - [Authors](#authors) 50 | - [Acknowledgments](#acknowledgments) 51 | - [Quick Access Links](#quick-access-links) 52 | - [LeetCode](#leetcode) 53 | - [1-Two Sum](#1-two-sum) 54 | - [Brute Force](#brute-force) 55 | - [One Pass Hash Table](#one-pass-hash-table) 56 | - [2-Add Two Numbers](#2-add-two-numbers) 57 | - [Elementary Math Solution](#elementary-math-solution) 58 | - [3-Substring No Repeat](#3-substring-no-repeat) 59 | - [Brute Force](#brute-force-1) 60 | - [Sliding Window](#sliding-window) 61 | - [Sliding Window Optimized](#sliding-window-optimized) 62 | - [4-Median of Two Sorted Arrays](#4-median-of-two-sorted-arrays) 63 | - [Recursive Approach](#recursive-approach) 64 | - [5-Longest Palindromic Substring](#5-longest-palindromic-substring) 65 | - [Longest Common Substring](#longest-common-substring) 66 | - [Brute Force](#brute-force-2) 67 | - [Dynamic Programming](#dynamic-programming) 68 | - [Expand Around Center](#expand-around-center) 69 | - [Manacher's Algorithm](#manachers-algorithm) 70 | - [6-ZigZag Conversion](#6-zigzag-conversion) 71 | - [Sort by Row](#sort-by-row) 72 | - [Visit by Row](#visit-by-row) 73 | - [7-Reverse Integer](#7-reverse-integer) 74 | - [Pop and Push Digits and Check Before Overflow](#pop-and-push-digits-and-check-before-overflow) 75 | - [8-String to Integer (atoi)](#8-string-to-integer-atoi) 76 | - [ASCII Conversion](#ascii-conversion) 77 | - [9-Palindrome Number](#9-palindrome-number) 78 | - [Revert Half of the Number](#revert-half-of-the-number) 79 | - [10-Regular Expression Matching](#10-regular-expression-matching) 80 | - [Recursion](#recursion) 81 | - [Dynamic Programming](#dynamic-programming-1) 82 | - [Non-Recursive](#non-recursive) 83 | - [11-Container with the Most Water](#11-container-with-the-most-water) 84 | - [Brute Force](#brute-force-3) 85 | - [Two Pointer Approach](#two-pointer-approach) 86 | - [12-Integer To Roman](#12-integer-to-roman) 87 | - [String Array](#string-array) 88 | - [13-Roman to Integer](#13-roman-to-integer) 89 | - [Character Array](#character-array) 90 | - [14-Longest Common Prefix](#14-longest-common-prefix) 91 | - [Horizontal Scanning](#horizontal-scanning) 92 | - [Vertical Scanning](#vertical-scanning) 93 | - [Divide and Conquer](#divide-and-conquer) 94 | - [Binary Search](#binary-search) 95 | - [Further Thoughts](#further-thoughts) 96 | - [15-3Sum](#15-3sum) 97 | - [Sorted Array](#sorted-array) 98 | - [16-3Sum Closest](#16-3sum-closest) 99 | - [3 Pointers](#3-pointers) 100 | - [17-Letter Combinations of a Phone Number](#17-letter-combinations-of-a-phone-number) 101 | - [Backtracking](#backtracking) 102 | - [First In First Out (FIFO) Queue](#first-in-first-out-fifo-queue) 103 | - [18-4Sum](#18-4sum) 104 | - [Sorted Array](#sorted-array-1) 105 | - [19-Remove Nth Node From End of List](#19-remove-nth-node-from-end-of-list) 106 | - [Two Pass Algorithm](#two-pass-algorithm) 107 | - [One Pass Algorithm](#one-pass-algorithm) 108 | - [20-Valid Parentheses](#20-valid-parentheses) 109 | - [Counting method](#counting-method) 110 | - [Stacks](#stacks) 111 | - [21-Merge Two Sorted Lists](#21-merge-two-sorted-lists) 112 | - [Recursive](#recursive) 113 | - [Non-Recursive](#non-recursive-1) 114 | - [22-Generate Parentheses](#22-generate-parentheses) 115 | - [Brute Force](#brute-force-4) 116 | - [Backtracking](#backtracking-1) 117 | - [Closure Number](#closure-number) 118 | - [23-Merge k Sorted Lists](#23-merge-k-sorted-lists) 119 | - [Brute Force](#brute-force-5) 120 | - [146-LRU Cache](#146-lru-cache) 121 | 122 | 123 | 124 | 125 |




126 | *** 127 |


128 | 129 | 130 | # 1-Two Sum 131 | 132 | Given an array of integers, return **indices** of the two numbers such that they add up to a specific target. 133 | You may assume that each input would have **exactly one solution**, and you may not use the same element twice. 134 | 135 | Example: 136 | ``` 137 | Given nums = [2, 7, 11, 15], target = 9, 138 | 139 | Because nums[0] + nums[1] = 2 + 7 = 9, 140 | return [0, 1]. 141 | ``` 142 | 143 |

144 | 145 | ## Brute Force 146 | 147 | ```java 148 | public int[] twoSum(int[] nums, int target) { 149 | for (int i=0; i 165 | ## One Pass Hash Table 166 | 167 | ```java 168 | public int[] twoSum(int[] nums, int target) { 169 | Map map = new HashMap<>(); 170 | for(int i=0; i

187 | *** 188 | 189 | # 2-Add Two Numbers 190 | 191 | Given two non-empty linked lists representing two non-negative integers with the digits stored in 192 | reverse order and each node containing a single digit, add the two numbers and return as a linked list 193 | 194 | Example: 195 | ``` 196 | Input (2 -> 4 -> 3) + (5 -> 6 -> 4) 197 | Output 7 -> 0 -> 8 198 | 199 | 342 + 465 = 807 200 | ``` 201 | 202 | 203 |

204 | 205 | ## Elementary Math Solution 206 | 207 | ```java 208 | /** 209 | * Definition for singly-linked list. 210 | * public class ListNode { 211 | * int val; 212 | * ListNode next; 213 | * ListNode(int x) { val = x; } 214 | * } 215 | */ 216 | 217 | 218 | 219 | class Solution { 220 | public ListNode addTwoNumbers(ListNode l1, ListNode l2) { 221 | ListNode dummyHead= new ListNode(0); 222 | ListNode p=l1, q=l2, curr=dummyHead; 223 | int carry=0; 224 | while (p!=null||q!=null){ 225 | int x= (p!=null) ? p.val :0; //if (p!=null) then x contains p.val 226 | int y= (q!=null) ? q.val :0; 227 | int sum=carry+x+y; 228 | carry=sum/10; 229 | curr.next=new ListNode(sum%10); 230 | curr=curr.next; 231 | if (p!=null) p=p.next; 232 | if (q!=null) q=q.next; 233 | } 234 | if (carry>0){ 235 | curr.next= new ListNode(carry); 236 | } 237 | return dummyHead.next; 238 | } 239 | } 240 | ``` 241 | 242 | **Complexity analysis** 243 | ``` 244 | * Time Complexity: O(max(m,n)) depends on the lengths of the two linked lists 245 | * Space Complexity: O(max(m,n)) the maximum length of the new list is max(m,n)+1 246 | ``` 247 | 248 | 249 |


250 | *** 251 | 252 | # 3-Substring No Repeat 253 | 254 | Longest Substring Without Repeating Characters 255 | 256 | Given a string find the length of the longest substring without repeating characters. 257 | 258 | ``` 259 | Example 260 | Input: "abcabcbb" 261 | Output: 3 262 | Explanation: The answer is "abc", with the length of 3 263 | ``` 264 | ``` 265 | Example 2 266 | Input: "bbbbb" 267 | Output: 1 268 | Explanation: The answer is "b", with the length of 1 269 | ``` 270 | ``` 271 | Example 3 272 | Input: "pwwkew" 273 | Output: 3 274 | Explanation: The answer is "wke", with the length of 3. Note that the answer must be a substring 275 | "pwke" is a subsequence and not a substring 276 | ``` 277 | 278 |

279 | 280 | ## Brute Force 281 | 282 | *Algorithm* 283 | 284 | 285 | Suppose we have a function "boolean allUnique(String substring)" which returns true if all the 286 | characters in the substring are unique and false otherwise. We can iterate through all the possible 287 | substrings of the given string s and call the function allUnique. If it turns out to be true, then we 288 | update our answer of the maximum length of substring without duplicate characters. 289 | 290 | To enumerate all substrings of a given string we enumerate the start and end indices of them. Suppose 291 | the start and end indices are i and j respectively. Then we have 0 <= i <= j <= n. Thus using two 292 | nested loops with i from 0 to n-1 and j from i+1 to n, we can enumerate all the substrings of s 293 | 294 | To check if one string has duplicate characters we can use a set. We iterate through all the 295 | characters in the string and put them into the set one by one. Before putting one character, we check 296 | if the set already contains it. If so we return false and after the loop we return true. 297 | 298 | 299 | ```java 300 | public class Solution { 301 | public int lengthOfLongestSubstring(String s) { 302 | int n = s.length(); 303 | int ans = 0; 304 | for (int i = 0; i < n; i++) 305 | for (int j = i + 1; j <= n; j++) 306 | if (allUnique(s, i, j)) ans = Math.max(ans, j - i); 307 | return ans; 308 | } 309 | 310 | public boolean allUnique(String s, int start, int end) { 311 | Set set = new HashSet<>(); 312 | for (int i = start; i < end; i++) { 313 | Character ch = s.charAt(i); 314 | if (set.contains(ch)) return false; 315 | set.add(ch); 316 | } 317 | return true; 318 | } 319 | } 320 | ``` 321 | 322 | **Complexity Analysis** 323 | 324 | ``` 325 | * Time Complexity: O(n^3) Verifying if characters in [i,j) are unique requires us to scan all of 326 | them which would cost O(j-i) time. 327 | 328 | For a given i, the sum of time costed by each j -> [i+1,n] is 329 | "Summation from i+1 to n O(j-1)" 330 | 331 | Thus, the sum of all the time consumption is: 332 | O(summation from 0 to n-1(summation from j=i+1 to n (j-1))) 333 | O(summation from i=0 to n-1(1+n-i)(n-i)/2)) = O(n^3) 334 | 335 | 336 | *Note that the sum of all numbers up to n 1+2+3+...+n = n(n+1)/2 337 | 338 | 339 | * Space Complexity: O(min(n,m)) We require O(k) space for checking a substring has no duplicate 340 | characters, where k is the size of the set. The size of the Set is 341 | upper bounded by the size of the string n amd the size of the charset 342 | or alphabet m 343 | 344 | 345 | ``` 346 | 347 |

348 | 349 | ## Sliding Window 350 | 351 | A sliding window is an abstract concept commonly used in array/string problems. A window is a range of 352 | elements in the array/string which usually defined by the start and end indices 353 | ``` 354 | Ex. [i,j) left-closed, right-open 355 | ``` 356 | A sliding window is a window that slides its two boundaries in a certain direction, for example if we 357 | slide \[i,j) to the right by 1 element, then it becomes \[i+1, j+1) - left closed, right open. 358 | 359 | 360 | 361 | Sliding Window approach, whenever we are looking at a section on an array usual to perform calculations 362 | we don't need to completely recalculate everything for every section of the array. Usually we can use 363 | the value obtained from another section of the array to determine something about this section of the 364 | array. For example if we are calculating the sum of sections of an array we can use the previously 365 | calculated value of a section to determine the sum of an adjacent section in the array. 366 | ``` 367 | Ex. 1 2 3 4 5 6 7 8 368 | ``` 369 | If we calculate the first section of four values we get 1+2+3+4 = 10 , then to calculate the next section 370 | 2+3+4+5 we can just take our first section (window_sum) and perform the operation: 371 | ``` 372 | window_sum-first entry + last entry = 10-1+5= 14 373 | ``` 374 | So essentially for the window sliding technique we use what we know about an existing window to 375 | determine properties for another window. 376 | 377 |

378 | *Algorithm* 379 | 380 | In the brute force approach, we repeatedly check a substring to see if it has duplicate characters but 381 | this is unnecessary. If a substring from index i to j-1 is already checked to have no duplicate 382 | characters we only need to check if s[j] is already in the substring. 383 | 384 | To check if a character is already in the substring we can scan the substring which leads to an O(n^2) 385 | algorithm but we can improve on this runtime using a HashSet as a sliding window to check if a 386 | character exists in the current set O(1). 387 | 388 | We use a HashSet to store the characters in the current window \[i,j) and then we slide the index j to 389 | the right, if it is not in the HashSet, we slide j further until s[j] is already in the HashSet. At 390 | this point we found the maximum size of substrings without duplicate characters starting with index i. 391 | If we do this for all i, then we obtain our answer. 392 | 393 | 394 | ```java 395 | public class Solution { 396 | public int lengthOfLongestSubstring(String s) { 397 | int n = s.length(); 398 | Set set = new HashSet<>(); 399 | int ans = 0, i = 0, j = 0; 400 | while (i < n && j < n) { 401 | // try to extend the range [i, j] 402 | if (!set.contains(s.charAt(j))){ 403 | set.add(s.charAt(j++)); 404 | ans = Math.max(ans, j - i); 405 | } 406 | else { 407 | set.remove(s.charAt(i++)); 408 | } 409 | } 410 | return ans; 411 | } 412 | } 413 | ``` 414 | 415 | **Complexity Analysis** 416 | ``` 417 | Time complexity: O(2n)=O(n) Worst case each character will be visited twice by i and j 418 | 419 | Space complexity: O(min(m,n)) Same as the brute force method, we need O(k) space for the 420 | sliding window where k is the size of the set. The size of the 421 | set is bounded by the size of the string n and the size of the 422 | charset/alphabet m 423 | ``` 424 | 425 | 426 |

427 | 428 | ## Sliding Window Optimized 429 | 430 | The previously discussed sliding window approach requires at most 2n steps and this could in fact be 431 | optimized even further to require only n steps. Instead of using a set to tell if a character exists or 432 | not, we could define a mapping of the characters to its index. Then we can skip the characters 433 | immediately when we found a repeated character 434 | 435 | If s[j] has a duplicate in the range \[i , j) with index j', we don't need to increase i little be little 436 | we can just skip all the elements in the range \[i , j'] and let i be j'+1 directly 437 | 438 | ```java 439 | public class Solution { 440 | public int lengthOfLongestSubstring(String s) { 441 | int n = s.length(), ans = 0; 442 | Map map = new HashMap<>(); // current index of character 443 | // try to extend the range [i, j] 444 | for (int j = 0, i = 0; j < n; j++) { 445 | if (map.containsKey(s.charAt(j))) { 446 | i = Math.max(map.get(s.charAt(j)), i); 447 | } 448 | ans = Math.max(ans, j - i + 1); 449 | map.put(s.charAt(j), j + 1); 450 | } 451 | return ans; 452 | } 453 | } 454 | ``` 455 | 456 |


457 | *** 458 | 459 | # 4-Median of Two Sorted Arrays 460 | 461 | There are two sorted arrays num1 and num2 of size m and n respectively. Find the median of the two 462 | sorted arrays. The overall run time complexity should be O(log (m+n)). You may assume nums1 and nums2 463 | cannot be both empty. 464 | 465 | ``` 466 | Example 467 | 468 | nums1 = [1, 3] 469 | nums2 = [2] 470 | 471 | The median is 2.0 472 | ``` 473 | 474 | ``` 475 | Example 2 476 | 477 | nums1= [1, 2] 478 | nums2= [3, 4] 479 | 480 | The median is (2+3)/2 = 2.5 481 | ``` 482 | 483 | 484 |

485 | 486 | ## Recursive Approach 487 | 488 | In statistics the median is used for dividing a set into two equal length subsets with one set being 489 | always greater than the other set. To approach this problem first we cut A into two parts at a random 490 | position i: 491 | 492 | ``` 493 | left_A | right_A 494 | 495 | A[0], A[1], ... , A[i-1] A[i], A[i+1], ... , A[m-1] 496 | ``` 497 | 498 | Since A has m elements, there are m+1 kinds of cutting as i can range from 0-m. We can also see that 499 | left_A is empty when i is zero and right_A is empty when i=m 500 | 501 | ``` 502 | len(left_A) = i and len(right_A)= m-i 503 | ``` 504 | 505 | We can similarly cut B into two parts at a random position j: 506 | 507 | ``` 508 | left_B | right_B 509 | 510 | B[0], B[1], ... , B[j-1] B[j], B[j+1], ... , B[n-1] 511 | ``` 512 | 513 | Now if we put left_A and left_B into one set and put right_A and right_B into another set and name 514 | them left_part and right_part, then we get 515 | 516 | ``` 517 | left_part | right_part 518 | A[0], A[1], ... , A[i-1] A[i], A[i+1], ... , A[m-1] 519 | B[0], B[1], ... , B[j-1] B[j], B[j+1], ... , B[n-1] 520 | ``` 521 | 522 | If we can ensure that 523 | 1. the len(left_part) = len(right_part) 524 | 2. max(left_part) <= min(right_part) 525 | 526 | then we divide all the elements in {A,B} into two parts with equal length and one part is always 527 | greater than the other. Then 528 | 529 | ``` 530 | median= (max(left_part)+min(right_part))/2 531 | ``` 532 | To ensure these two conditions, we need to ensure: 533 | 1. i+j= m-i+n-j (or: m-i+n-j+1) if n>m, we just need to set i=0~m, j= (m+n+1)/2 - i 534 | 2. B\[j-1]<=A\[i] and A\[i-1]<=B\[j] 535 | 536 | So, all we need to do is search for i in \[0,m] to find an object i such that 537 | B\[j-1]<=A\[i] and A\[i-1]<=B\[j] where j=(m+n+1)/2 -i 538 | 539 | Then we perform a binary search following the steps described below: 540 | 541 | 1) Set imin=0, imax=0, then start searching in \[imin, imax] 542 | 2) Set i=(imin+imax)/2 , j=(m+n+1)/2 - i 543 | 3) Now we have len(left_part) = len(right_part) and there are only 3 more situations which we may 544 | encounter: 545 | 546 | ``` 547 | - B[j-1] <= A[i] and A[i-1]<=B[j] 548 | This means that we have found the object i, so we can stop searching 549 | 550 | - B[j-1] > A[i] 551 | Means A[i] is too small, we must adjust i to get B[j-1]<=A[i] so we increase i because this will 552 | cuase j to be decreased. We cannot decrease i because when i is decreased, j will be increased 553 | so B[j-1] is increased and A[i] is decreased (B[j-1]<= A[i] will never be satisfied) 554 | 555 | - A[i-1] > B[j] 556 | Means A[i-1] is too big and thus we must decrease i to get A[i-1]<=B[j]. In order to do that we 557 | must adjust the searching range to [imin, i-1] so we set imax=i-1 and go back to step 2 558 | ``` 559 | When the object i is found, then the media is: 560 | 561 | max(A\[i-1],B\[j-1]), when m+n is odd 562 | (max(A\[i-1],B\[j-1])+min(A\[i],B\[j]))/2, when m+n is even 563 | 564 | Next is to consider the edge values i=0, i=m, j=0, j=n where A\[i-1], B\[j-1], A\[i], B\[j] may not exist 565 | 566 | ```java 567 | class Solution { 568 | public double findMedianSortedArrays(int[] A, int[] B) { 569 | int m=A.length; 570 | int n=B.length; 571 | if (m>n) { //ensuring that m<=n 572 | int[] temp=A; A=B; B=temp; 573 | int tmp=m; m=n; n=tmp; 574 | } 575 | int iMin=0, iMax=m, halfLen=(m+n+1)/2; 576 | while (iMin<=iMax) { 577 | int i=(iMin+iMax)/2 578 | int j= halfLen - i; 579 | if (i A[i]){ 580 | iMin=i+1; //i is too small 581 | } 582 | else if (i>iMin && A[i-1]>B[j]) { 583 | iMax=i-1; //i is too big 584 | } 585 | else{ //we have found the object i 586 | int maxLeft=0; 587 | if (i==0) { 588 | maxLeft=B[j-1]; 589 | } 590 | else if (j==0){ 591 | maxLeft=A[i-1]; 592 | } 593 | else{ 594 | maxLeft=Math.max(A[i-1], B[j-1]); 595 | } 596 | 597 | if ((m+n)%2 ==1) { 598 | return maxLeft; 599 | } 600 | 601 | int minRIght=0; 602 | if (i==m) { 603 | minRight=B[j]; 604 | } 605 | else if (j==n) { 606 | minRight=A[i]; 607 | } 608 | else { 609 | minRight=Math.min(B[j], A[i]); 610 | } 611 | 612 | return (maxLeft+minRight)/2.0; 613 | } 614 | } 615 | return 0.0; 616 | } 617 | } 618 | ``` 619 | 620 | **Complexity Analysis** 621 | 622 | ``` 623 | Time Complexity: O(log(min(m,n))) At first the searching range is [0,m] and the length of this 624 | searching range will be reduced by half after each loop so we 625 | only need log(m) loops. Since we do constant operations in 626 | each loop the time complexity is O(log(m) and since m<=n the 627 | time complexity is O(log(min(m,n)) 628 | 629 | Space Complexity: O(1) We only need constant memory to store 9 local variables so the 630 | space complexity is O(1) 631 | ``` 632 | 633 | 634 |


635 | *** 636 | 637 | # 5-Longest Palindromic Substring 638 | 639 | Given a string s, find the longest palindromic substring in s. You may assume that the maximum length 640 | of s is 1000. 641 | 642 | ``` 643 | Example 1: 644 | 645 | Input: "babad" 646 | Output: "bab" 647 | 648 | Note: "aba" is also a valid answer 649 | ``` 650 | 651 | ``` 652 | Example 2: 653 | 654 | Input: "cbbd" 655 | Output: "bb" 656 | ``` 657 | 658 |

659 | 660 | ## Longest Common Substring 661 | 662 | Some people will be tempted to come up with this quick solution which is unforunately flawed, "reverse 663 | S and become S'. Find the longest common substring between S and S' and that will be the longest 664 | palindromic substring." This will work with some examples but there are some cases where the longest 665 | common substring is not a valid palindrome. 666 | 667 | Ex. S="abacdfgdcaba", S'="abacdgfdcaba" 668 | 669 | The longest common substring between S and S' is "abacd" and clearly this is not a valid 670 | palindrome 671 | 672 | We can solve this problem however by checking if the substring's indices are the same as the reversed 673 | substring's original indices each time we find a longest common substring. If it is, then we attempt 674 | to update the longest palindrome found so far, if not we skip this and find the next candidate 675 | 676 | **Complexity Analysis** 677 | ``` 678 | Time Complexity: O(n^2) 679 | Space Complexity: O(n^2) 680 | ``` 681 |

682 | 683 | ## Brute Force 684 | 685 | The obvious brute force solution is to pick all possible starting and ending position for a substring 686 | and verify if it is a palindrome 687 | 688 | **Complexity Analysis** 689 | ``` 690 | Time Complexity: O(n^3) If n is the length of the input string, there are a total of 691 | (n 2) = n(n-1)/2 substrings and since verifying each substring takes 692 | O(n) time, the run time complexity is O(n^3) 693 | 694 | Space Complexity: O(1) 695 | ``` 696 |

697 | 698 | ## Dynamic Programming 699 | 700 | We can improve on the brute force solution by avoid some unnecessary re-computation while validating 701 | palidromes. Consider the word "ababa", if we already know that "bab" is a palindrome then we can 702 | determine that ababa is a palindrome by noticing that the two left and right letters connected to bab 703 | are the same. 704 | 705 | This yields a straight forward dynamic programming solution where we initialize the one and two letters 706 | palindromes and then work our way up finding all three letters palindromes and so on. 707 | 708 | **Complexity Analysis** 709 | ``` 710 | Time Complexity: O(n^2) 711 | 712 | Space Complexity: O(n^2) Using O(n^2) space to store the table 713 | ``` 714 |

715 | 716 | ## Expand Around Center 717 | 718 | This approach allows us to solve this problem in O(n^2) time using only constant space complexity. We 719 | observe that a palindrome mirrors around its enter and therefore a palindrome can be expanded from its 720 | center and there are only 2n-1 such centers (for palindromes with an even number of letters like 721 | "abba" its center is in between two letters). 722 | 723 | ```java 724 | public String longestPalindrome(String s) { 725 | if (s==null || s.length() < 1) return ""; //edge case 726 | int start=0, end=0; 727 | for (int i=0; iend-start) { 732 | start= i-(len-1)/2; 733 | end=i+len/2 734 | } 735 | } 736 | return s.substring(start,end+1); 737 | } 738 | 739 | private int expandAroundCenter(String s, int left, int right) { 740 | int L=left, R=right; 741 | while(L>=0 && R
750 | 751 | ## Manacher's Algorithm 752 | 753 | There is an O(n) algorithm called Manacher's algorithm, however, it is a non-trivial algorithm and no 754 | one would expect you to come up with this algorithm in a 45 minute coding session 755 | 756 | 757 |


758 | *** 759 | 760 | # 6-ZigZag Conversion 761 | 762 | The string "PAYPALISHIRING" is written in a zigzag pattern on a given number of rows like this: 763 | ``` 764 | P A H N 765 | A P L S I I G 766 | Y I R 767 | ``` 768 | And then read line by line: "PAHNAPLSIIGYIR". Write a code that will take a string and make this 769 | conversion given a number of rows: 770 | 771 | ``` 772 | string convert(string s, int numRows); 773 | ``` 774 | 775 | ``` 776 | Example 1: 777 | 778 | Input: s="PAYPALISHIRING", numRows=3 779 | Output: "PAHNAPLSIIGYIR" 780 | ``` 781 | 782 | ``` 783 | Example 2: 784 | 785 | Input: s="PAYPALISHIRING", numRows=4 786 | Output: "PINALSIGYAHRPI" 787 | 788 | Explanation: 789 | 790 | P I N 791 | A L S I G 792 | Y A H R 793 | P I 794 | ``` 795 | 796 |

797 | 798 | ## Sort by Row 799 | 800 | By iterating through the string from left to right we can easily determine which row in the Zig-Zag 801 | pattern that a character belongs to 802 | 803 |

804 | *Algorithm* 805 | 806 | We can use min(numRows,len(s)) lists to represent the non-empty rows of the Zig-Zag Pattern. 807 | Iterate through s from left to right appending each character to the appropriate row. The appropriate 808 | row can be tracked using two variables: the current row and the current direction. 809 | 810 | The current direction only changes when we moved to the topmost row or moved down to the bottommost 811 | row 812 | 813 | ```java 814 | class Solution { 815 | public String convert(String s, int numRows) { 816 | if (numRows==1) return s; //if there is only one row return string 817 | 818 | List rows=new ArrayList<>(); 819 | for (int i=0; i
850 | 851 | ## Visit by Row 852 | 853 | Visit the characters in the same order as reading the Zig-Zag pattern line by line 854 | 855 |

856 | *Algorithm* 857 | 858 | Visit all characters in row 0 first, then row 1, then row 2, and so on. 859 | For all whole numbers k, 860 | * characters in row 0 are located at indexes k\*(2\*numRows-2) 861 | * characters in row numRows -1 are located at indexes k\*(2\*numRows-2)+ numRows -1 862 | * characters in inner row i are located at indexes k\*(2\*numRows-2)+i and (k+1)(2\*numRows-2)-i 863 | 864 | ```java 865 | class Solution { 866 | public String convert(String s, int numRows) { 867 | if (numRows==1) return s; 868 | 869 | StringBuilder ret=new StringBuilder(); 870 | int n=s.length(); 871 | int cycleLen= 2* numRows -2; 872 | 873 | for (int i=0; i

896 | *** 897 | 898 | # 7-Reverse Integer 899 | 900 | Given a 32- bit signed integer, reverse digits of an integer. 901 | 902 | ``` 903 | Example 1: 904 | 905 | Input: 123 906 | Output: 321 907 | ``` 908 | 909 | ``` 910 | Example 2: 911 | 912 | Input: -123 913 | Output: -321 914 | ``` 915 | 916 | ``` 917 | Example 3: 918 | 919 | Input: 120 920 | Output: 21 921 | ``` 922 | 923 | For the purpose of this problem assume that your function returns 0 when the reversed integer overflows 924 | 925 |

926 | 927 | ## Pop and Push Digits and Check Before Overflow 928 | 929 | We can build up the reverse integer one digit at and time and before doing so we can check whether or 930 | not appedning another digit would cause overflow 931 | 932 |

933 | *Algorithm* 934 | 935 | Reversing an integer can be done similarly to reversing a string. We want to repeatedly "pop" the last 936 | digit off of x and push it to the back of the rev so that in the end rev is the reverse of x. 937 | 938 | To push and pop digits without the help of some auxiliar stack/array we can use math 939 | 940 | ``` 941 | //pop operation: 942 | pop = x%10; 943 | x/=10; 944 | 945 | //push operation: 946 | temp=rev*10+pop; 947 | rev =temp; 948 | ``` 949 | 950 | This statement is dangerous however as the statement temp=rev\*10+pop may cause an overflow and luckily 951 | it is easy to check beforehand whether or not this statement would cause an overflow. 952 | 953 | 1. If temp=rev\*10+pop causes an overflow, then rev>=INTMAX/10 954 | 2. If rev> INTMAX/10, then temp=rev\*10+pop is guaranteed to overflow 955 | 3. if rev==INTMAX/10, then temp=rev\*10 + pop will overflow if an only if pop>7 956 | 957 | ```java 958 | class Solution { 959 | public int reverse(int x) { 960 | int rev=0; 961 | while (x!=0) { 962 | int pop=x%10; 963 | x/=10; 964 | if (rev>Integer.MAX_VALUE/10||(rev==Integer.MAX_VALUE/10 && pop>7)) return 0; 965 | if (rev

981 | *** 982 | 983 | # 8-String to Integer (atoi) 984 | 985 | Implement atoi which converts a string to an integer 986 | 987 | The function first discards as many whitespace characters as necessary until the first non-whitespace 988 | character is found. Then, starting from this character, takes an optional initial plus or minus sign 989 | followed by as many numerical digits as possible and interprets them as a numerical value. 990 | 991 | The string can contain additional characters after those that form the integral number, which are 992 | ignored and have no effect on the behavior of this function. 993 | 994 | If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such 995 | sequence exits because either str is empty or it contains only whitespace characters, no conversion is 996 | performed. 997 | 998 | If no valid conversion could be performed a zero value is returned 999 | 1000 | Note: 1001 | * only the space character ' ' is considered as whitespace character 1002 | * assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [-2^31, 2^31-1]. If the numerical value is out of the range of representable values, INT_MAX (2^31-1) or INT_MIN (-2^31) is returned 1003 | 1004 | ``` 1005 | Example 1: 1006 | 1007 | Input: "42" 1008 | Output: 42 1009 | ``` 1010 | 1011 | ``` 1012 | Example 2: 1013 | 1014 | Input: " -42" 1015 | Output: -42 1016 | ``` 1017 | 1018 | ``` 1019 | Example 3: 1020 | 1021 | Input: "4193 with words " 1022 | Output: 4193 1023 | ``` 1024 | 1025 | ``` 1026 | Example 4: 1027 | 1028 | Input: "words and 987" 1029 | Output: 0 1030 | ``` 1031 | 1032 | ``` 1033 | Example 5: 1034 | 1035 | Input: "-91283472332" 1036 | Output: -2147483648 //out of the range of a 32-bit signed integer so INT_MIN is returned 1037 | ``` 1038 | 1039 | 1040 |

1041 | 1042 | ## ASCII Conversion 1043 | 1044 | Recognize that ASCII characters are actually numbers and 0-9 digits are numbers starting from decimal 1045 | 48 (0x30 hexadecimal) 1046 | 1047 | ``` 1048 | '0' is 48 1049 | '1' is 49 1050 | ... 1051 | '9' is 57 1052 | ``` 1053 | So to get the value of any character digit you can just remove the '0' 1054 | 1055 | ``` 1056 | '1' - '0' => 1 1057 | 49 - 48 => 1 1058 | ``` 1059 | 1060 | ```java 1061 | public int myAtoi(String str) { 1062 | int index=0, sign=1, total=0; 1063 | 1064 | //1. Empty string 1065 | if (str.length() ==0) return 0; 1066 | 1067 | //2. Remove Spaces 1068 | while(str.charAt(index)==' ' && index < str.length()) 1069 | index++; 1070 | 1071 | //3. Handle signs 1072 | if (str.charAt(index)=='+' || str.charAt(index)=='-'){ 1073 | sign= str.charAt(index) == '+' ? 1:-1; 1074 | index++; 1075 | } 1076 | 1077 | //4. COnvert number and avoid overflow 1078 | while(index9) break; 1081 | 1082 | //check if total will overflow after 10 times and add digit 1083 | if (Integer.MAX_VALUE/10 < total || Integer.MAX_VALUE/10 == total 1084 | && Integer.MAX_VALUE%10

1096 | *** 1097 | 1098 | # 9-Palindrome Number 1099 | 1100 | 1101 | Determines whether an interger is a palindrome. An integer is a palindrome when it reads the same 1102 | backward as forward. 1103 | 1104 | ``` 1105 | Example 1: 1106 | 1107 | Input: 121 1108 | Output: true 1109 | ``` 1110 | 1111 | ``` 1112 | Example 2: 1113 | 1114 | Input: -121 1115 | Output: false 1116 | Explanation: From left to right, it reads -121, meanwhile from right to left it becomes 121- . 1117 | Therefore it is not a palindrome 1118 | ``` 1119 | 1120 | ``` 1121 | Example 3: 1122 | 1123 | Input: 10 1124 | Output: false 1125 | Explanation: Reads 01 from right to left. Therefore it is not a palindrome 1126 | ``` 1127 | 1128 | 1129 |

1130 | 1131 | ## Revert Half of the Number 1132 | 1133 | A first idea which may come to mind is to convert the number into a string and check if the string is a 1134 | palindrome but this would require extra non-constant space for creating the string not allowed by the 1135 | problem description 1136 | 1137 | Second idea would be reverting the number itself and comparing the number with the original number, if 1138 | they are the same then the number is a palindrome, however if the reversed number is larger than 1139 | int.MAX we will hit integer overflow problem. 1140 | 1141 | To avoid the overflow issue of the reverted number, what if we only revert half of the int number? The 1142 | reverse of the last half of the palindrome should be the same as the first half of the number if the 1143 | number is a palindrome. 1144 | 1145 | If the input is 1221, if we can revert the last part of the number "1221" from "21" to "12" and compare 1146 | it with the first half of the number "12", since 12 is the same as 12, we know that the number is a 1147 | palindrome. 1148 | 1149 |

1150 | *Algorithm* 1151 | 1152 | At the very beginning we can deal with some edge cases. All negative numbers are not palindrome and 1153 | numbers ending in zero can only be a palindrome if the first digit is also 0 (only 0 satisfies this 1154 | property) 1155 | 1156 | Now let's think about how to revert the last half of the number. For the number 1221 if we do 1221%10 1157 | we get the last digit 1. To get the second last digit we divide the number by 10 1221/10=122 and then 1158 | we can get the last digit again by doing a modulus by 10, 122%10=2. If we multiply the last digit by 1159 | 10 and add the second last digit 1\*10+2=12 which gives us the reverted number we want. COntinuing this 1160 | process would give us the reverted number with more digits. 1161 | 1162 | Next is how do we know that we've reached the half of the number? 1163 | Since we divided the number by 10 and multiplied the reversed number by 10 when the original number is 1164 | less than the reversed number, it means we've gone through half of the number digits. 1165 | 1166 | ```java 1167 | class Solution { 1168 | public boolean isPalindrome(int x) { 1169 | if (x<0 || (x%10==0 && x!=0)) { 1170 | return false; 1171 | } 1172 | 1173 | int revertedNumber=0; 1174 | while (x>revertedNumber){ 1175 | revertedNumber=x%10+revertedNumber*10; 1176 | x/=10; 1177 | } 1178 | //when the length is an odd number, we can get rid of the middle digit by 1179 | //revertedNumber/10 1180 | 1181 | //For example when the input is 12321, at the end of the while loop we get x=12, 1182 | //revertedNumber=123, since the middle digit doesn't matter in a palindrome we can 1183 | //simply get rid of it 1184 | 1185 | return x==revertedNumber||x==revertedNumber/10; 1186 | } 1187 | } 1188 | ``` 1189 | 1190 | 1191 |


1192 | *** 1193 | 1194 | # 10-Regular Expression Matching 1195 | 1196 | Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' 1197 | and '*' 1198 | 1199 | ``` 1200 | '.' Matches any single character 1201 | '*' Matches zero or more of the preceding element 1202 | ``` 1203 | The matching should cover the entire input string (not partial) 1204 | 1205 | Note: 1206 | * s could be empty and contains only lower case letters a-z 1207 | * p could be empty and contains only lower case letters a-z and characters like . or * 1208 | 1209 | ``` 1210 | Example 1: 1211 | 1212 | Input: 1213 | s="aa" 1214 | p="a" 1215 | Output: false 1216 | Explanation: "a" does not match the entire string "aa" 1217 | ``` 1218 | 1219 | ``` 1220 | Example 2: 1221 | 1222 | Input: 1223 | s="aa" 1224 | p="a*" 1225 | Output: true 1226 | Explanation: '*' means zero of more of the preceding element, 'a'. Therefore, by repeating 1227 | 'a' once it becomes "aa" 1228 | ``` 1229 | 1230 | ``` 1231 | Example 3: 1232 | 1233 | Input: 1234 | s="ab" 1235 | p=".*" 1236 | Output: true 1237 | Explanation: '.*' means "zero or more (*) of any character (.)" 1238 | ``` 1239 | 1240 | ``` 1241 | Example 4: 1242 | 1243 | Input: 1244 | s="aab" 1245 | p="c*a*b" 1246 | Output: true 1247 | Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches 1248 | "aab" 1249 | ``` 1250 | 1251 | ``` 1252 | Example 5: 1253 | 1254 | Input: 1255 | s="mississippi" 1256 | p="mis*is*p*." 1257 | Output: false 1258 | ``` 1259 | 1260 |

1261 | 1262 | ## Recursion 1263 | 1264 | If there were no Kleene stars (the * wildcard characters for regular expressions), the problem would 1265 | be easier- we simply check from left to right if each character of the text matches the pattern. When 1266 | a star is present we may need to check for may different suffixes of the text and see if they match 1267 | the rest of the pattern. A recursive solution is a straightforward way to represent this relationship 1268 | 1269 | ```java 1270 | class Solution { 1271 | public boolean isMatch(String text, String pattern) { 1272 | if (pattern.isEmpty()) return text.isEmpty(); 1273 | 1274 | boolean first_match=(!text.isEmpty() && 1275 | (pattern.charAt(0)==text.charAt(0) || pattern.charAt(0)=='.')); 1276 | 1277 | if (pattern.length()>=2 && pattern.charAt(1) =='*'){ 1278 | return (isMatch(text,pattern.substring(2))|| 1279 | (first_match && isMatch(text.substring(1),pattern))); 1280 | 1281 | //note: pattern.substring(2) returns all of the characters after index 2 of pattern 1282 | } 1283 | else { 1284 | return first_match && isMatch(text.substring(1), pattern.substring(1)); 1285 | } 1286 | 1287 | } 1288 | } 1289 | ``` 1290 | 1291 | **Complexity Analysis** 1292 | 1293 | ``` 1294 | Time Complexity: Let T, P be the lengths of the text and the pattern respectively. In the worst 1295 | case, a call to match(text[i:],pattern[2j:]) will be made (i+j i) times, and 1296 | strings of the order O(T-i) and O(P-2*j) will be made. Thus the complexity has 1297 | the order: 1298 | 1299 | summation from i=0 to T * summation from j=0 to P/2 * (i+j i) O(T+P-i-2j). 1300 | 1301 | We can show that this is bounded by O((T+P)2^(T+P/2)) 1302 | 1303 | Space Complexity: For every call to match, we will create those strings as described above 1304 | possibly creating duplicates. If memory is not freed, this will also take a 1305 | total of O((T+P)2^(T+P/2)) space even though there are only order O(T^2+P^2) 1306 | unique suffixes of P and T that are actually required 1307 | ``` 1308 | 1309 |

1310 | 1311 | ## Dynamic Programming 1312 | 1313 | As the problem has an optimal substructure, it is natural to cache intermediate results. We ask the 1314 | question dp(i,j): does text[i:] and pattern[j:] match? We can describe our answer in terms of answers 1315 | to questions involving smaller strings 1316 | 1317 |

1318 | *Algorithm* 1319 | 1320 | We proceed with the same recursion as in Approach 1, except because calls will only ever be made to 1321 | match(text[i:], pattern[j:]), we use dp(i,j) to handle those calls instead, saving us expensive 1322 | string-building operations and allowing us to cache the intermediate results 1323 | 1324 | 1325 | **Java Top-Down Variation** 1326 | 1327 | ```java 1328 | enum Result { 1329 | TRUE, FALSE 1330 | 1331 | } 1332 | 1333 | class Solution { 1334 | Result[][] memo; 1335 | 1336 | public boolean isMatch(String text, String pattern) { 1337 | memo=new Result[text.length() +1][pattern.length() +1]; 1338 | return dp(0,0,text,pattern); 1339 | } 1340 | 1341 | public boolean dp(int i, int j, String text, String pattern) { 1342 | if (memo[i][j]!=null) { 1343 | return memo[i][j]==Result.TRUE; 1344 | } 1345 | boolean ans; 1346 | if (j==pattern.length()){ 1347 | ans=i==text.length(); 1348 | } 1349 | else { 1350 | boolean first_match=(i
1377 | 1378 | ## Non-Recursive 1379 | 1380 | The recursive programming solutions are pretty confusing so this implementation uses 2D arrays and 1381 | Dynamic Programming 1382 | 1383 | 1384 | The logic works as follows: 1385 | ``` 1386 | 1. If p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1]; 1387 | 2. If p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1]; 1388 | 3. If p.charAt(j) == '*': 1389 | 1390 | Subconditions 1391 | 1. If p.charAt(j-1)!= s.charAt(i):dp[i][j]=dp[i][j-2] //in this case a* only counts as empty 1392 | 2. If p.charAt(i-1)== s.charAt(i) or p.charAt(i-1) == '.': 1393 | 1394 | dp[i][j] = dp[i-1][j] //in this case a* counts as multiple a 1395 | or dp[i][j] = dp[i][j-1] //in this case a* counts as single a 1396 | or dp[i][j] = dp[i][j-2] //in this case a* counts as empty 1397 | ``` 1398 | 1399 | ```java 1400 | public boolean isMatch(String s, String p) { 1401 | if (s==null || p==null){ 1402 | return false; 1403 | } 1404 | boolean[][] dp=new boolean[s.length()+1][p.length()+1]; 1405 | dp[0][0]=true; 1406 | for (int i=0;i

1435 | *** 1436 | 1437 | # 11-Container with the Most Water 1438 | 1439 | Given n non negative integers a1,a2, ... , an where each represents a point at coordinate (i, ai). n 1440 | vertical lines are drawn such that the two endpoints of line i is at (i, ai) and (i, 0). Find two 1441 | lines, which together with x-axis forns a container such that the container contains the most water. 1442 | 1443 | ```Example: The array [1,8,6,2,5,4,8,3,7] would have a max area of water which is 49. 1444 | 1445 | ^ ^ 1446 | These two values form the container which could hold water at a max height of 7, these values 1447 | are also 7 array indexes apart from each other so it could hold water at a max width of 7. The 1448 | area of water which could be held is thus 7 x 7 = 49 1449 | ``` 1450 | 1451 | 1452 | 1453 | ## Brute Force 1454 | 1455 | In this case we simply consider the area for every possible pair of the lines and find out the maximum 1456 | area out of those. 1457 | 1458 | ``` 1459 | public class Solution { 1460 | public int maxArea(int[] height) { 1461 | int maxarea=0; 1462 | for (int i=0; i
1479 | 1480 | ## Two Pointer Approach 1481 | 1482 | The intuition behind this approach is that the area formed between the lines will always be limited by 1483 | the height of the shorter line. Further, the farther the lines, the more will be the area obtained. 1484 | 1485 | We take two pointers, one at the beginning and one at the end of the array constituting the length of 1486 | the lines. Further, we maintain a variable maxarea to store the maximum area obtained till now. At 1487 | every step, we find out the area formed between them, update maxarea and move the pointer pointing to 1488 | the shorter line towards the other end by one step. 1489 | 1490 | Initially we consider the area constituting the exterior most lines. Now to maximize the area we need 1491 | to consider the area between the lines of larger lengths. If we try to move the pointer at the longer 1492 | line inwards, we won't gain any increase in area, since it is limited by the shorter line. But moving 1493 | the shorter line's pointer could turn out to be benefical, as per the same argument, despite the 1494 | reduction in width. This is done since a relatively longer line obtained by moving the shorter line's 1495 | pointer might overcome the reduction in area caused by the width reduction. 1496 | 1497 | ```java 1498 | public class Solution { 1499 | public int maxArea(int[] height) { 1500 | int maxarea=0, l=0, r=height.length-1; 1501 | while (l

1522 | *** 1523 | 1524 | # 12-Integer To Roman 1525 | 1526 | Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M 1527 | ``` 1528 | Symbol Value 1529 | I 1 1530 | V 5 1531 | X 10 1532 | L 50 1533 | C 100 1534 | D 500 1535 | M 1000 1536 | ``` 1537 | 1538 | For example, two is written as II in Roman numeral, just two one's added together. Twelve is written as 1539 | XII which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II. 1540 | 1541 | Roman numerals are usually written largest to smallest from left to right. However, the numeral for 1542 | four is not IIII. Instead, the number four is written as IV. Because the one is before the five we 1543 | subtract it making four. The same principle applies to the number nine which is written as IX. There 1544 | are six instances where subtraction is used: 1545 | 1546 | * I can be placed before V (5) and X (10) to make 4 and 9 1547 | * X can be placed before L (50) and C(100) to make 40 and 90 1548 | * C can be placed before D (500) and M(1000) to make 400 and 900 1549 | 1550 | Given an integer, convert it to a roman numeral, input is guaranteed to be within the range from 1551 | 1 to 3999 1552 | 1553 | ``` 1554 | Example 1: 1555 | 1556 | Input: 3 1557 | Output: "III" 1558 | ``` 1559 | 1560 | ``` 1561 | Example 2: 1562 | 1563 | Input: 4 1564 | Output: "IV" 1565 | ``` 1566 | 1567 | ``` 1568 | Example 3: 1569 | 1570 | Input: 9 1571 | Output: "IX" 1572 | ``` 1573 | 1574 | ``` 1575 | Example 4: 1576 | 1577 | Input: 58 1578 | Output: "LVIII" 1579 | Explanation: L=50, V=5, III=3 1580 | ``` 1581 | 1582 | ``` 1583 | Example 5: 1584 | 1585 | Input: 1994 1586 | Output: "MCMXCIV" 1587 | Explanation: M=1000, CM=900, XC=90 and IV=4 1588 | ``` 1589 | 1590 | 1591 | ## String Array 1592 | 1593 | ```java 1594 | public static String intToRoman(int num) { 1595 | 1596 | String M[]={"", "M", "MM", "MMM"}; 1597 | //represents 1000, 2000, and 3000 since we know the number is in the range 1 to 3999 1598 | 1599 | String C[]={"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; 1600 | //represents 0, 100, 200, 300, 400, 500, 600, 700, 800, 900 1601 | 1602 | String X[]={"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; 1603 | //represents 0, 10, 20, 30, 40, 50, 60, 70, 80, 90 1604 | 1605 | String I[]={"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; 1606 | //represents 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 1607 | 1608 | return M[num/1000] + C[(num%1000)/100] + X[(num%100)/10] + I[num%10]; 1609 | } 1610 | ``` 1611 | 1612 |


1613 | *** 1614 | 1615 | # 13-Roman to Integer 1616 | 1617 | Roman numerals are represented by seven different symbols I, V, X, L, C, D and M 1618 | ``` 1619 | Symbol Value 1620 | I 1 1621 | V 5 1622 | X 10 1623 | L 50 1624 | C 100 1625 | D 500 1626 | M 1000 1627 | ``` 1628 | 1629 | For example, two is written as II in Roman numeral, just two one's added together. Twelve is written as 1630 | XII which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II. 1631 | 1632 | Roman numerals are usually written largest to smallest from left to right. However, the numeral for 1633 | four is not IIII. Instead, the number four is written as IV. Because the one is before the five we 1634 | subtract it making four. The same principle applies to the number nine which is written as IX. There 1635 | are six instances where subtraction is used: 1636 | 1637 | * I can be placed before V (5) and X (10) to make 4 and 9 1638 | * X can be placed before L (50) and C(100) to make 40 and 90 1639 | * C can be placed before D (500) and M(1000) to make 400 and 900 1640 | 1641 | Given an integer, convert it to a roman numeral, Input is guaranteed to be within the range from 1642 | 1 to 3999 1643 | 1644 | ``` 1645 | Example 1: 1646 | 1647 | Input: "III" 1648 | Output: 3 1649 | ``` 1650 | 1651 | ``` 1652 | Example 2: 1653 | 1654 | Input: "IV" 1655 | Output: 4 1656 | ``` 1657 | 1658 | ``` 1659 | Example 3: 1660 | 1661 | Input: "IX" 1662 | Output: 9 1663 | ``` 1664 | 1665 | ``` 1666 | Example 4: 1667 | 1668 | Input: "LVIII" 1669 | Output: 58 1670 | Explanation: L=50, V=5, III=3 1671 | ``` 1672 | 1673 | ``` 1674 | Example 5: 1675 | 1676 | Input: "MCMXCIV" 1677 | Output: 1994 1678 | Explanation: M=1000, CM=900, XC=90 and IV=4 1679 | ``` 1680 |

1681 | 1682 | ## Character Array 1683 | 1684 | ```java 1685 | class Solution { 1686 | public int romanToInt(String s) { 1687 | Map map = new HashMap(); 1688 | map.put('I', 1); 1689 | map.put('V', 5); 1690 | map.put('X', 10); 1691 | map.put('L', 50); 1692 | map.put('C', 100); 1693 | map.put('D', 500); 1694 | map.put('M', 1000); 1695 | 1696 | char[] sc= s.toCharArray(); 1697 | int total= map.get(sc[0]); 1698 | int pre=map.get(sc[0]); 1699 | for (int i=1; i

1716 | *** 1717 | 1718 | # 14-Longest Common Prefix 1719 | 1720 | Write a function to find the longest common prefix string amongst an array of strings. If there is no 1721 | common prefix, return an empty string "" 1722 | 1723 | ``` 1724 | Example 1: 1725 | 1726 | Input: ["flower", "flow", "flight"] 1727 | Output: "fl" 1728 | ``` 1729 | 1730 | ``` 1731 | Example 2: 1732 | 1733 | Input: ["dog", "racecar", "car"] 1734 | Output: "" 1735 | 1736 | Explanation: There is no common prefix among the input strings 1737 | ``` 1738 | 1739 | *Note:* 1740 | All given inputs are in lowercase letters a-z 1741 | 1742 |

1743 | 1744 | ## Horizontal Scanning 1745 | 1746 |
1747 | *Intuition:* 1748 | 1749 | For a start we will describe a simple way of find the longest prefix shared by a set of strings 1750 | LCP(S1 ... Sn).We will use the observation that: 1751 | ``` 1752 | LCP(S1 ... Sn) = LCP(LCP(LCP(S1, S2), S3), ... Sn) 1753 | ``` 1754 | 1755 |

1756 | *Algorithm:* 1757 | 1758 | To employ this idea, the algorithm iterates through the strings [S1 ... Sn]. finding at each iteration 1759 | i the longest common prefix of strings LCP(S1 ... Si). When LCP(S1 ... Si) is an empty string, the 1760 | algorithm ends. Otherwise after n iterations, the algorithm returns LCP(S1 ... Sn) 1761 | 1762 | ``` 1763 | 1764 | Example: 1765 | 1766 | {leets, leetcode, leet, leeds} 1767 | \ / 1768 | LCP{1,2} = leets 1769 | leetcode 1770 | leet 1771 | 1772 | \ {leets, leetcode, leet, leeds} 1773 | \ / 1774 | 1775 | LCP{1,3} = leet 1776 | leet 1777 | leet 1778 | 1779 | \ {leets, leetcode, leet, leeds} 1780 | \ / 1781 | LCP{1,4} leet 1782 | leeds 1783 | lee 1784 | 1785 | LCP{1,4} = "lee" 1786 | ``` 1787 | 1788 | ```java 1789 | public String longestCommon Prefix(String[] strs){ 1790 | if (strs.length==0){ 1791 | return ""; 1792 | } 1793 | String prefix=strs[0]; 1794 | for (int i=1; i
1818 | 1819 | ## Vertical Scanning 1820 | 1821 | Imagine a very short string is at the end of the array. The above approach will still do S comparisons. 1822 | One way to optimize this case is to do vertical scanning. We compare characters from top to bottom on 1823 | the same column (same character index of the strings) before moving on to the next column. 1824 | 1825 | 1826 | ```java 1827 | public String longestCommonPrefix(String[] strs) { 1828 | if (strs==null || strs.length==) return ""; 1829 | for (int i=0; i
1854 | 1855 | ## Divide and Conquer 1856 | 1857 | The idea of the algorithm comes from the associative property of LCP operation. We notice that: 1858 | LCP(S1 ... Sn) = LCP(LCP(S1 ... Sk), LCP(Sk+1 ... Sn)), where LCP(S1 ... Sn) is the longest common 1859 | prefix in a set of strings [S1 ... Sn], 1
1862 | *Algorithm* 1863 | 1864 | To apply the previous observation, we use the divide and conquer technique, where we split the 1865 | LCP(Si ... Sj) problem into two subproblems LCP(Si ... Smid) and LCP(Smid+1 ... Sj), where mid is 1866 | (i+j)/2. We use their solutions lcpLeft and lcpRight to construct the solution of the main problem 1867 | LCP(Si ... Sj). To accomplish this we compare one by one the characters of lcpLeft and lcpRight till 1868 | there is no character match. The found common prefix of lcpLeft and lcpRight is the solution of the 1869 | LCP(Si ... Sj) 1870 | 1871 | 1872 | ``` 1873 | {leetcode, leet, lee, le} 1874 | 1875 | / \ 1876 | Divide {leetcode, leet} {lee, le} 1877 | 1878 | Conquer | | 1879 | 1880 | {leet} {le} 1881 | 1882 | \ / 1883 | 1884 | {le} 1885 | 1886 | Searching for the longest common prefix (LCP) in dataset {leetcode, leet, lee, le} 1887 | ``` 1888 | 1889 | ```java 1890 | public String longestCommonPrefix(String[] strs) { 1891 | 1892 | if (strs == null || strs.length ==0) return ""; 1893 | return longestCommonPrefix(strs, 0, strs.length-1); 1894 | 1895 | } 1896 | 1897 | private String longestCommonPrefix(String[] strs, int l, int r) { 1898 | if (l==r) { 1899 | return strs[l]; 1900 | } 1901 | else { 1902 | int mid=(l+r)/2; 1903 | String lcpLeft= longestCommonPrefix(strs,l, mid); 1904 | String lcpRight= longestCommonPrefix(strs,mid+1;r); 1905 | return commonPrefix(lcpLeft,lcpRight); 1906 | } 1907 | } 1908 | 1909 | String commonPrefix(String left, String right) { 1910 | int min=Math.min(left.length(), right.length()); 1911 | for (int i=0; i
1936 | 1937 | ## Binary Search 1938 | 1939 | The idea is to apply binary search method to find the string with maximum value L, which is common 1940 | prefix of all the strings. The algorithm searches the space in the interval (0 ... minLen), where 1941 | minLen is minimum string length and the maximum possible common prefix. Each time search space is 1942 | divided in two equal parts, one of them is discarded because it is sure that it doesn't contain the 1943 | solution. There are two possible cases: 1944 | 1945 | * S[1...mid] is not a common string. This means that for each j>i, S[1...j] is not a common string and we discard the second half of the search space 1946 | * S [1...mid] is common string. This means that for each i
2022 | 2023 | ## Further Thoughts 2024 | 2025 | Considering a slightly different problem: 2026 | ``` 2027 | Given a set of keys S= [S1, S2 ... Sn], find the longest common prefix among a string q and S. 2028 | This LCP query will be called frequently 2029 | ``` 2030 | We coule optimize LCP queries by storing the set of keys S in a Trie. See this for [Trie 2031 | implementation](#trie). In a Trie, each node descending from the root represents a common prefix of some keys. But we need to 2032 | find the longest common prefix of a string q and all key strings. This means that we have to find the 2033 | deepest path from the root, which satisfies the following conditions 2034 | 2035 | * it is a prefix of query string q 2036 | * each node along the path must contain only one child element. Otherwise the found path will not be a 2037 | common prefix among all strings 2038 | * the path doesn't comprise of nodes which are marked as end of key. Otherwise the path couldn't be a 2039 | prefix of a key which is shorter than itself 2040 | 2041 |

2042 | *Algorithm* 2043 | 2044 | The only question left is how to find the deepest path in the Trie, that fulfills the requirements 2045 | above. The most effective way is to build a trie from {S1 ... Sn] strings. Then find the prefix of 2046 | query string q in the Trie. We traverse the Trie from the root, till it is impossible to continue the 2047 | path in the Trie because one of the conditions above is not satisfied. 2048 | 2049 | 2050 | ``` 2051 | Searching for the longest common prefix of string "le" in a Trie from dataset {lead, leet} 2052 | 2053 | Root 2054 | 2055 | 1 2056 | 2057 | l ===========> \ l 2058 | 2059 | 2 2060 | 2061 | e ===============> \ e 2062 | 2063 | LCP "le" FOUND =============> 3 2064 | 2065 | a / \ e End of Key "lee" 2066 | 2067 | 6 4 2068 | 2069 | d / \ t 2070 | 2071 | END OF KEY "lead" 7 5 End of key "leet" 2072 | ``` 2073 | 2074 | 2075 | 2076 | ``` 2077 | public String longestCommonPrefix(String q, String[] strs) { 2078 | if (strs == null || strs.length == 0) 2079 | return ""; 2080 | if (strs.length == 1) 2081 | return strs[0]; 2082 | Trie trie = new Trie(); 2083 | for (int i = 1; i < strs.length ; i++) { 2084 | trie.insert(strs[i]); 2085 | } 2086 | return trie.searchLongestPrefix(q); 2087 | } 2088 | 2089 | class TrieNode { 2090 | 2091 | // R links to node children 2092 | private TrieNode[] links; 2093 | 2094 | private final int R = 26; 2095 | 2096 | private boolean isEnd; 2097 | 2098 | // number of children non null links 2099 | private int size; 2100 | public void put(char ch, TrieNode node) { 2101 | links[ch -'a'] = node; 2102 | size++; 2103 | } 2104 | 2105 | public int getLinks() { 2106 | return size; 2107 | } 2108 | //assume methods containsKey, isEnd, get, put are implemented as it is described 2109 | //in https://leetcode.com/articles/implement-trie-prefix-tree/) 2110 | } 2111 | 2112 | public class Trie { 2113 | 2114 | private TrieNode root; 2115 | 2116 | public Trie() { 2117 | root = new TrieNode(); 2118 | } 2119 | 2120 | //assume methods insert, search, searchPrefix are implemented 2121 | private String searchLongestPrefix(String word) { 2122 | TrieNode node = root; 2123 | StringBuilder prefix = new StringBuilder(); 2124 | for (int i = 0; i < word.length(); i++) { 2125 | char curLetter = word.charAt(i); 2126 | if (node.containsKey(curLetter) && (node.getLinks() == 1) && (!node.isEnd())) { 2127 | prefix.append(curLetter); 2128 | node = node.get(curLetter); 2129 | } 2130 | else 2131 | return prefix.toString(); 2132 | 2133 | } 2134 | return prefix.toString(); 2135 | } 2136 | } 2137 | ``` 2138 | 2139 | **Complexity Analysis** 2140 | ``` 2141 | In the worst case query q has length m and is equal to all n strings of the array 2142 | 2143 | Time Complexity: O(S) where S is the number of all characters in the array, LCP query O(m) 2144 | Trie build has O(S) time complexity. To find the common prefix of q 2145 | in the Trie takes in the worst O(m). 2146 | 2147 | Space complexity: O(S) we only used additional S extra space for the Trie. 2148 | ``` 2149 | 2150 | 2151 |


2152 | *** 2153 | 2154 | # 15-3Sum 2155 | 2156 | 2157 | Given an array "nums" of n integers, are there elements a, b, c in nums such that a+b+c=0? Find all 2158 | unique triplets in the array which gives the sum of zero. 2159 | 2160 | Note: 2161 | 2162 | The solution set must not contain duplicate triplets 2163 | 2164 | ``` 2165 | Example: 2166 | 2167 | Given array nums = [-1, 0, 1, 2, -1, -4]. 2168 | 2169 | A solution set is: 2170 | [ 2171 | [-1, 0, 1], 2172 | [-1, -1, 2] 2173 | ] 2174 | ``` 2175 |

2176 | 2177 | ## Sorted Array 2178 | 2179 | 2180 | The method is to sort an input array and then run through all indices of a possible first element of a 2181 | triplet. For each element we make another 2Sum sweep of the remaining part of the array. Also we want 2182 | to skip elements to avoid duplicates in the answer without expending extra memory. 2183 | 2184 | ``` 2185 | public List> threeSum(int[] num) { 2186 | 2187 | //Arrays.sort re-arranges the array of integers in ascending order 2188 | //ex. [1, 2, 3, 4] 2189 | 2190 | Arrays.sort(num); 2191 | List> res = new LinkedList<>(); 2192 | for (int i = 0; i < num.length-2; i++) { 2193 | if (i == 0 || (i > 0 && num[i] != num[i-1])) { 2194 | 2195 | //This lets us skip some of the duplicate entries in the array 2196 | 2197 | int lo = i+1, hi = num.length-1, sum = 0 - num[i]; 2198 | 2199 | //This is for the 2 Sum sweep 2200 | 2201 | while (lo < hi) { 2202 | if (num[lo] + num[hi] == sum) { 2203 | res.add(Arrays.asList(num[i], num[lo], num[hi])); 2204 | while (lo < hi && num[lo] == num[lo+1]) lo++; 2205 | while (lo < hi && num[hi] == num[hi-1]) hi--; 2206 | 2207 | //This lets us skip some of the duplicate entries in the array 2208 | 2209 | lo++; hi--; 2210 | } else if (num[lo] + num[hi] < sum) lo++; 2211 | else hi--; 2212 | 2213 | //This allows us to optimize slightly since we know that the array is sorted 2214 | } 2215 | } 2216 | } 2217 | return res; 2218 | } 2219 | ``` 2220 | 2221 | **Complexity Analysis** 2222 | ``` 2223 | Time Complexity: O(n^2) We go through a maximum of n elements for the first element of a triplet, 2224 | and then when making a bi-directional 2Sum sweep of the remaining part of 2225 | the array we also go through a maxiumum of n elements. 2226 | 2227 | Space Complexity: O(1) If we assume the return linked list is not extra space, then we do not 2228 | allocate any significant extra space 2229 | ``` 2230 | 2231 | 2232 | 2233 |


2234 | *** 2235 | 2236 | # 16-3Sum Closest 2237 | 2238 | Given an array nums of n integers and an integer target, find three integers in nums such that the sum 2239 | is closest to target. Return the sum of the three integers. You may assume that each input would have 2240 | exactly one solution. 2241 | 2242 | ``` 2243 | Example: 2244 | 2245 | Given array nums=[-1, 2, 1, -4], and target=1. 2246 | 2247 | The sum that is closest to the target is 2. (-1+2+1=2) 2248 | ``` 2249 | 2250 |

2251 | 2252 | ## 3 Pointers 2253 | 2254 | Similar to the previous 3Sum problem, we use three pointers to point to the current element, next 2255 | element and the last element. If the sum is less than the target, it means that we need to add a larger 2256 | element so next element move to the next. If the sum is greater, it means we have to add a smaller 2257 | element so last element move to the second last element. Keep doing this until the end. Each time 2258 | compare the difference between sum and target, if it is less than minimum difference so far, then 2259 | replace result with it, otherwise continue iterating. 2260 | 2261 | ``` 2262 | public class Solution { 2263 | public int threeSumClosest(int[] num, int target) { 2264 | int result=num[0] + num[1] + num[num.length-1]; 2265 | Arrays.sort(num); 2266 | for (int i=0; i target) { 2271 | end--; 2272 | } else { 2273 | start++; 2274 | } 2275 | if (Math.abs(sum-target) < Math.abs(result-target)) { 2276 | result=sum; 2277 | } 2278 | } 2279 | } 2280 | return result; 2281 | } 2282 | } 2283 | ``` 2284 | 2285 | 2286 |


2287 | *** 2288 | 2289 | # 17-Letter Combinations of a Phone Number 2290 | 2291 | Given a string contianing digits from 2-9 inclusive, return all possible letter combinations that the 2292 | number could represent. 2293 | 2294 | A mapping of digit to letters (just like on the telephone buttons) is given below. Note that 1 does not 2295 | map to any letters. 2296 | 2297 | ``` 2298 | 2 - abc 3 - def 4 - ghi 5 - jkl 6 - mno 7 - pqrs 8 - tuv 2299 | 2300 | 9 - wxyz 2301 | ``` 2302 | 2303 | 2304 | ``` 2305 | Example: 2306 | 2307 | 2308 | Input: "23" 2309 | 2310 | Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. 2311 | ``` 2312 | 2313 | 2314 | *Note: The above answer is in lexicographical order but the answer can be in any order* 2315 | 2316 |

2317 | 2318 | ## Backtracking 2319 | 2320 | 2321 | Backtracking is an algorithm for finding all solutions by exploring all potential candidates. If the 2322 | solution candidate turns to not be a solution (or at least not the last one), backtracking algorithm 2323 | discards it by making some changes on the previous step, ie *backtracks* and then tries again. 2324 | 2325 | Here is a backtrack function backtrack(combination, next_digits) which takes as arguments an ongoing 2326 | letter combination and the next digits to check. 2327 | 2328 | * If there are no more digits to check that means the current combination is done 2329 | * If there are still digits to check: 2330 | * Iterate over the letters mapping to the next available digit 2331 | * Append the current letter to the current combination and proceed to check next digits: 2332 | 2333 | 2334 | ``` 2335 | combination = combination + letter 2336 | 2337 | backtrack(combination + letter, next_digits[1:]). 2338 | ``` 2339 | 2340 | 2341 | **Visual Representation** 2342 | 2343 | ``` 2344 | 2345 | "2 3" 2346 | 2347 | 2348 | 2 2349 | 2350 | / | \ 2351 | 2352 | a b c 2353 | 2354 | 2355 | / | \ 2356 | 2357 | 2358 | 3 3 3 2359 | 2360 | / | \ / | \ / | \ 2361 | 2362 | d e f d e f d e f 2363 | 2364 | 2365 | ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"] 2366 | ``` 2367 | 2368 | ```java 2369 | class Solution { 2370 | Map phone = new HashMap() {{ 2371 | put("2", "abc"); 2372 | put("3", "def"); 2373 | put("4", "ghi"); 2374 | put("5", "jkl"); 2375 | put("6", "mno"); 2376 | put("7", "pqrs"); 2377 | put("8", "tuv"); 2378 | put("9", "wxyz"); 2379 | }}; 2380 | 2381 | List output = new ArrayList(); 2382 | 2383 | public void backtrack(String combination, String next_digits) { 2384 | 2385 | 2386 | //if there are no more digits to check 2387 | if (next_digits.length()==0) { 2388 | 2389 | //the combination is done 2390 | output.add(combination); 2391 | } 2392 | 2393 | 2394 | 2395 | //if there are still digits to check 2396 | else { 2397 | 2398 | //iterate over all letters which map the next available digit 2399 | String digit = next_digits.substring(0,1); 2400 | String letters = phone.get(digit); 2401 | for (int i=0; i letterCombinations(String digits) { 2411 | if (digits.length() !=0) { 2412 | backtrack("", digits); 2413 | } 2414 | return output; 2415 | } 2416 | } 2417 | ``` 2418 | 2419 | **Complexity Analysis** 2420 | 2421 | ``` 2422 | 2423 | Time Complexity: O(3^N * 4^M) where N is the number of digits in the input that maps to 3 2424 | letters (eg. 2, 3, 4, 5, 6, 8) and M is the number of digits 2425 | in the input that maps to 4 letters (eg. 7, 9) and N+M is the 2426 | total number digits in the input 2427 | 2428 | Space Complexity: O(3^N * 4^M) since one has to keep 3^N * 4^M solutions 2429 | ``` 2430 | 2431 | 2432 | 2433 |

2434 | 2435 | ## First In First Out (FIFO) Queue 2436 | 2437 | This solution utilizes the Single Queue Breadth First Search (BFS) which is an algorithm for traversing 2438 | or searching tree or graph data structures. It starts at the tree root and explores all of the neighbor 2439 | nodes. 2440 | 2441 | 2442 | ```java 2443 | public List letterCombinations(String digits) { 2444 | 2445 | LinkedList ans = new LinkedList(); 2446 | if (digits.isEmpty()) return ans; 2447 | String[] mapping = new String[] {"0", "1", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", {wxyz"}; 2448 | ans.add(""); 2449 | for (int i = 0; i

2483 | *** 2484 | 2485 | # 18-4Sum 2486 | 2487 | Given an array nums of n integers and an integer target, are there elements a, b, c, and d in nums such 2488 | that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target 2489 | 2490 | 2491 | 2492 | *Note:* 2493 | The solution set must not contain duplicate quadruplets 2494 | 2495 | 2496 | ``` 2497 | Example: 2498 | 2499 | 2500 | Given array nums = [1, 0, -1, 0, -2, 2], and target = 0 2501 | 2502 | 2503 | A solution set is: 2504 | 2505 | [ 2506 | [-1, 0, 0, 1], 2507 | [-2, -1, 1, 2], 2508 | [-2, 0, 0, 2] 2509 | ] 2510 | ``` 2511 | 2512 | 2513 |

2514 | 2515 | ## Sorted Array 2516 | 2517 | The idea is the same as the other numbered sum problems like 2sum and 3sum. We sort the array and then 2518 | proceed to interate through the values until we end up with a result that we are looking for. 2519 | 2520 | ```java 2521 | public class Solution { 2522 | public List> fourSum(int[] num, int target) { 2523 | 2524 | ArrayList> ans = new ArrayList<>(); 2525 | 2526 | if (num.length<4) { 2527 | 2528 | return ans; 2529 | } 2530 | Arrays.sort(num); 2531 | 2532 | for (int i=0; itarget) { 2536 | 2537 | break; 2538 | //first candidate too large, search finished 2539 | } 2540 | 2541 | if (num[i]+num[num.length-1]+num[num.length-2]+num[num.length-3]0 && num[i]==num[i-1]) { 2548 | 2549 | continue; 2550 | //prevents duplicate in ans list 2551 | } 2552 | 2553 | for (int j=i+1; jtarget) { 2557 | 2558 | break; 2559 | //second candidate too large 2560 | } 2561 | 2562 | if (num[i]+num[j]+num[num.length-1]+num[num.length-2]i+1 && num[j]==num[j-1]) { 2569 | 2570 | continue; 2571 | //prevents duplicate results in ans list 2572 | } 2573 | 2574 | int low=j+1, high=num.length-1; 2575 | 2576 | //two pointer search 2577 | while(low

2616 | *** 2617 | 2618 | # 19-Remove Nth Node From End of List 2619 | 2620 | Given a linked list, remove the n-th node from the end of the list and return its head 2621 | 2622 | ``` 2623 | Example: 2624 | 2625 | Given linked list: 1 -> 2 -> 3 -> 4 -> 5, and n=2 2626 | 2627 | 2628 | After removing the second node from the end, the linked list becomes 2629 | 2630 | 1 -> 2 -> 3 -> 5 2631 | ``` 2632 | 2633 | **Note:** 2634 | Given n will always be valid 2635 | 2636 | **Follow up:** 2637 | Could you do this in one pass? 2638 | 2639 | 2640 | 2641 | 2642 | 2643 | 2644 | 2645 | 2646 | 2647 |

2648 | 2649 | ## Two Pass Algorithm 2650 | 2651 | 2652 | **Intuition** 2653 | 2654 | We notice that the problem could be simply reduced to another one: Remove the (L-n+1)th node from the 2655 | beginning of the list, where L is the list length. This problem is easy to solve once we found the 2656 | list length L. 2657 | 2658 | 2659 | 2660 | 2661 | 2662 |

2663 | **Algorithm** 2664 | 2665 | First we will add an auxiliary "dummy" node, which points to the list head. The "dummy" node is used to 2666 | simplify some corner cases such as a list with only one node or removing the head of the list. On the 2667 | first pass, find the list length L. Then we set a pointer to the dummy node and start to move it 2668 | through the list till it comes to the (L-n)th node. We relink next pointer of the (L-n)th node to the 2669 | (L-n+2)th node and we are done. 2670 | 2671 | 2672 | ``` 2673 | D -> 1 -> 2 -> 3 -> 4 -> NULL 2674 | 2675 | | 2676 | v 2677 | 2678 | D -> 1 -> 2 -> 4 -> NULL 2679 | ``` 2680 | 2681 | 2682 | 2683 | ```java 2684 | public ListNode removeNthFromEnd(ListNode head, int n) { 2685 | 2686 | ListNode dummy = new ListNode(0); 2687 | dummy.next = head; 2688 | int length =0; 2689 | ListNode first = head; 2690 | 2691 | while (first!=null) { 2692 | 2693 | length++; 2694 | first=first.next; 2695 | } 2696 | 2697 | length -= n; 2698 | first = dummy; 2699 | while (length>0) { 2700 | 2701 | length--; 2702 | first=first.next; 2703 | } 2704 | first.next=first.next.next; 2705 | return dummy.next; 2706 | } 2707 | ``` 2708 | 2709 | **Complexity Analysis** 2710 | ``` 2711 | Time Complexity: O(L) The algorithm makes two traversals of the list, first to calculate the 2712 | list length L and second to find the (L-n)th node. There are 2L-n 2713 | operations and time complexity is O(L) 2714 | 2715 | Space Complexity: O(1) We only used constant extra space 2716 | ``` 2717 | 2718 | 2719 | 2720 | 2721 | 2722 |

2723 | 2724 | ## One Pass Algorithm 2725 | 2726 | The previous algorithm could be optimized to one pass. Instead of one pointer, we could use two 2727 | pointers. The first pointer advances the list by n+1 steps from the beginning, while the second pointer 2728 | starts from the beginning of the list. Now, both pointers are separated by exactly n nodes. We maintain 2729 | this constant gap by advancing both pointers together until the first pointer arrives past the last 2730 | node. The second pointer will be pointing at the nth node counting from the last. We relink the next 2731 | pointer of the node referenced by the second pointer to point to the node's next next node. 2732 | 2733 | 2734 | 2735 | ``` 2736 | Maintaining N=2 nodes apart between the first and second pointer 2737 | 2738 | D -> 1 -> 2 -> 3 -> 4 -> 5 -> NULL 2739 | 2740 | first Head 2741 | second 2742 | 2743 | 2744 | 2745 | 2746 | Move the first pointer N+1 steps 2747 | 2748 | 2749 | | 2750 | v 2751 | 2752 | 2753 | D -> 1 -> 2 -> 3 -> 4 -> 5 -> NULL 2754 | 2755 | second Head First 2756 | 2757 | 2758 | Move the first and second pointers together until the first pointer arrives past the last node 2759 | 2760 | 2761 | | 2762 | v 2763 | 2764 | 2765 | D -> 1 -> 2 -> 3 -> 4 -> 5 -> NULL 2766 | 2767 | Head Second First 2768 | 2769 | Second pointer points to the nth node counting from last so link node to the node's next next node 2770 | 2771 | 2772 | 2773 | | 2774 | v 2775 | 2776 | 2777 | D -> 1 -> 2 -> 3 -> -> 5 -> NULL 2778 | 2779 | Head Second First 2780 | ``` 2781 | 2782 | 2783 | ```java 2784 | public ListNode removeNthFromEnd(ListNode head, int n) { 2785 | 2786 | ListNode dummy = new ListNode(0); 2787 | dummy.next = head; 2788 | ListNode first = dummy; 2789 | ListNode second = dummy; 2790 | 2791 | //Moves the first pointer so that the first and second nodes are separated by n nodes 2792 | 2793 | for (int i=1; i<=n+1; i++) { 2794 | 2795 | first = first.next; 2796 | } 2797 | 2798 | //Move first to the end, maintaining the gap 2799 | 2800 | while (first!=null) { 2801 | 2802 | first=first.next; 2803 | second=second.next; 2804 | } 2805 | 2806 | second.next=second.next.next; 2807 | return dummy.next; 2808 | } 2809 | ``` 2810 | 2811 | 2812 | 2813 | **Complexity Analysis** 2814 | 2815 | ``` 2816 | Time Complexity: O(L) The algorithm makes one traversal of the list of L nodes. Therefore 2817 | time complexity is O(L) 2818 | 2819 | Space Complexity: O(1) Only constant extra space was used 2820 | ``` 2821 | 2822 | 2823 | 2824 | 2825 | 2826 | 2827 | 2828 |


2829 | *** 2830 | 2831 | # 20-Valid Parentheses 2832 | 2833 | 2834 | 2835 | Given a string containing just the characters '(', ')', '{', '}', '[', ']', determine if the input 2836 | string is valid 2837 | 2838 | An input string is valid if: 2839 | 2840 | 1. Open brackets must be closed by the same type of brackets 2841 | 2. Open brackets must be closed in the correct order 2842 | 2843 | Note that an empty string is also considered valid 2844 | 2845 | 2846 | ``` 2847 | Example 1: 2848 | 2849 | Input: "()" 2850 | Output: true 2851 | ``` 2852 | 2853 | 2854 | ``` 2855 | Example 2: 2856 | 2857 | Input: "()[]{}" 2858 | Output: true 2859 | ``` 2860 | 2861 | 2862 | ``` 2863 | Example 3: 2864 | 2865 | Input: "(]" 2866 | Output: false 2867 | ``` 2868 | 2869 | 2870 | ``` 2871 | Example 4: 2872 | 2873 | Input: "([)]" 2874 | Output: false 2875 | ``` 2876 | 2877 | 2878 | ``` 2879 | Example 5: 2880 | 2881 | Input: "{[]}" 2882 | Output: true 2883 | ``` 2884 | 2885 | 2886 | 2887 | 2888 | 2889 | 2890 |

2891 | 2892 | ## Counting method 2893 | 2894 | 2895 | 2896 | **Intuition** 2897 | 2898 | Imagine you are writing a small compiler for your college project and one of the tasks or sub-tasks for 2899 | the compiler would be to detect if the parenthesis are in place or not. 2900 | 2901 | 2902 | 2903 | The algorithm we will look at in this article can be then used to process all the parenthesis in the 2904 | program your compiler is compiling and checking if all the parenthesis are in place. This makes 2905 | checking if a given string of parenthesis is valid or not, an important programming problem. 2906 | 2907 | 2908 | 2909 | The expressions that we will deal with in this problem can consist of three different types of 2910 | parenthesis: 2911 | 2912 | 2913 | - () 2914 | - {} 2915 | - [] 2916 | 2917 | 2918 | Before looking at how we can check if a given expression consisting of thes parenthesis is valid or 2919 | not, let us look at a simpler version of the problem that consists of just one type of parenthesis. So, 2920 | the expressions we can encounter in this simplified version of the problem are: 2921 | 2922 | 2923 | ``` 2924 | (((((()))))) -- VALID 2925 | 2926 | ()()()() -- VALID 2927 | 2928 | (((((((() -- INVALID 2929 | 2930 | ((()(()))) -- VALID 2931 | ``` 2932 | 2933 | 2934 | Let's look at a simple algorithm to deal with this problem 2935 | 2936 |

2937 | 2938 | 1. We process the expression one bracket at a time starting from the left 2939 | 2. Suppose we encounter an opening bracket ie. `(`, it may or may not be an invalid expression because 2940 | there can be a matching ending bracket somewhere in the remaining part of the expression. Here, we 2941 | simply increment the counter keeping track of the left parenthesis till now. `left += 1` 2942 | 3. If we encounter a closing bracket, this has two meanings: 2943 | 2944 | - There was no matching opening bracket for this closing bracket and in that case we have an invalid 2945 | expression. This is the case when `left==0` ie. when there are no unmatched left brackets 2946 | available 2947 | 2948 | - We had some unmatched opening bracket available to match this closing bracket. This is the case 2949 | when `left>0` ie. we have unmatched left brackets available 2950 | 2951 | 4. If we encounter a closing bracket ie. `)` when left==0, then we have an invalid expression on our 2952 | hands. Else, we decrement `left` thus reducing the number of unmatched left parenthesis available. 2953 | 5. Continue processing the string until all parenthesis have been processed 2954 | 6. If in the end we still have an unmatched left parenthesis available, this implies an invalid 2955 | expression 2956 | 2957 |

2958 | 2959 | The reason we discussed this particular algorithm here is because the approach for the approach for 2960 | the original problem derives its inspiration from this very solution. 2961 | 2962 | 2963 | If we try and follow the same approach for our original problem, then it simply won't work. The reason 2964 | a simple counter based approach works above is because all the parenthesis are of the same type. So 2965 | when we encounter a closing bracket, we simply assume a corresponding opening matching bracket 2966 | to be available ie. if `left>0` 2967 | 2968 | 2969 | But in our problem, if we encounter say `]`, we don't really know if there is a corresponding opening 2970 | `[` available or not. You could say: 2971 | 2972 | > Why not maintain a separate counter for the different types of parenthesis? 2973 | 2974 | This doesn't work because the relative placement of the parenthesis also matters here eg: `[{]` 2975 | 2976 |

2977 | 2978 | If we simply keep counters here, then as soon as we encounter the closing square bracket, we would 2979 | know there is an unmatched opening square bracket available as well. But, the **closest unmatched 2980 | opening bracket available is a curly bracket and not a square bracket and hence the counting approach 2981 | breaks here. 2982 | 2983 | 2984 | 2985 | 2986 | 2987 | 2988 | 2989 |

2990 | 2991 | ## Stacks 2992 | 2993 | An interesting property about a valid parenthesis expression is that a sub-expression. (Not every 2994 | sub-expression) eg. 2995 | 2996 | ``` 2997 | { [ [ ] { } ] } ( ) ( ) 2998 | 2999 | ^ ^ 3000 | | | 3001 | ``` 3002 | 3003 | The entire expression is valid, but sub portions of it are also valid in themselves. This lends a sort 3004 | of a recursive structure to the problem. For example consider the expression enclosed within the 3005 | marked parenthesis in the diagram above. The opening bracket is at index `1` and the corresponding 3006 | closing bracket is at index `6`. 3007 | 3008 | 3009 | > What if whenever we encounter a matching pair of parenthesis in the expression we simply remove it 3010 | > from the expression? 3011 | 3012 | 3013 | Let's have a look at this idea below where we remove the smaller expressions one at a time from the 3014 | overall expression and since this is a valid expression, we would be left with an empty string in the 3015 | end. 3016 | 3017 | 3018 | ``` 3019 | The stack data structure can come in handy here in representing this recursive structure of the 3020 | problem. We can't really process this from the inside out because we don't have an idea about the 3021 | overall structure. But, the stack can help us process this recursively ie. from outside to inwards. 3022 | ``` 3023 | 3024 | Lets take a look at the algorithm for this problem using stacks as the intermediate data structure. 3025 | 3026 | 3027 | **Algorithm** 3028 | 3029 | 1. Initialize a stack S. 3030 | 2. Process each bracket of the expression one at a time 3031 | 3. If we encounter an opening bracket, we simply push it onto the stack. This means we will process it 3032 | later, let us simply move onto the sub-expression ahead 3033 | 4. If encounter a closing bracket, then we check the element on top of the stack. If the element at the 3034 | top of the stack is an opening bracket `of the same type`, then we pop it off the stack and continue 3035 | processing. Else, this implies an invalid expression 3036 | 5. In the end, if we are left with a stack still having elements, then this implies an invalid 3037 | expression 3038 | 3039 | Lets take a look at the implementation for this algorithm 3040 | 3041 | 3042 | 3043 | ```java 3044 | class Solution { 3045 | 3046 | //Hash table that takes care of the mappings 3047 | private HashMap mappings; 3048 | 3049 | //Initialize the hash map with mappings. This simply makes the code easier to read 3050 | public Solution() { 3051 | 3052 | this.mappings = new HashMap(); 3053 | this.mappings.put(')', '('); 3054 | this.mappings.put('}', '{'); 3055 | this.mappings.put(']', '['); 3056 | } 3057 | 3058 | public boolean isValid(String s) { 3059 | 3060 | // Initialize a stack to be used in the algorithm 3061 | Stack stack = new Stack(); 3062 | 3063 | for (int i=0; i< s.length(); i++) { 3064 | 3065 | char c = s.charAt(i); 3066 | 3067 | // If the current character is a closing bracket 3068 | 3069 | if (this.mappings.containsKey(c)) { 3070 | 3071 | // Get the top element of the stack. If the stack is empty, set a dummy value of '#' 3072 | char topElement = stack.empty() ? '#' : stack.pop(); 3073 | 3074 | // If the mapping for this bracket doesn't match the stack's top element, return false. 3075 | if (topElement != this.mappings.get(c)) { 3076 | return false; 3077 | } 3078 | } else { 3079 | 3080 | //If it was an opening bracket, push to the stack 3081 | 3082 | stack.push(c); 3083 | } 3084 | } 3085 | 3086 | //If the stack still contains elements, then it is an invalid expression. 3087 | return stack.isEmpty(); 3088 | } 3089 | } 3090 | ``` 3091 | 3092 | **Complexity Analysis** 3093 | 3094 | ``` 3095 | Time Complexity: O(n) We simply traverse the given string one character at a time and push 3096 | and pop operations on a stack take O(1) time 3097 | 3098 | Space Complexity: O(n) In the worst case, when we push all opening brackets onto the stack, we 3099 | will end up pushing all the brackets onto the stack eg ((((((((((( 3100 | ``` 3101 | 3102 | 3103 |


3104 | *** 3105 | 3106 | # 21-Merge Two Sorted Lists 3107 | 3108 | Merge two sorted linked lists and return it as a new list. The new list should be made by splicing 3109 | together the nodes of the first two lists. 3110 | 3111 | 3112 | ``` 3113 | Example: 3114 | 3115 | Input: 1->2->4, 1->3->4 3116 | Output: 1->1->2->3->4->4 3117 | ``` 3118 | 3119 | 3120 | 3121 |

3122 | 3123 | ## Recursive 3124 | 3125 | ```java 3126 | class solution { 3127 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 3128 | 3129 | if (l1 == null) return l2; 3130 | if (l2 == null) return l1; 3131 | if (l1.val < l2.val) { 3132 | 3133 | l1.next = mergeTwoLists(l1.next, l2); 3134 | return l1; 3135 | } else { 3136 | 3137 | l2.next = mergeTwoLists(l1, l2.next); 3138 | return l2; 3139 | } 3140 | } 3141 | } 3142 | ``` 3143 | 3144 | 3145 |

3146 | 3147 | ## Non-Recursive 3148 | 3149 | Similar approach and implemenation to the recursive solution above but a little more intuitive and 3150 | does not require memory being held on the stack (as the recursive program runs it has to store 3151 | variables on the stack so that when the program jumps back it is able to continue) 3152 | 3153 | 3154 | As with most other linked list solutions, a dummy node is utilized and two pointers are used to keep 3155 | track of where we are in the the two linked lists. 3156 | 3157 | ```java 3158 | class solution { 3159 | public ListNode mergeTwoLists(ListNode l1, ListNode l2) { 3160 | 3161 | ListNode returnNode = new ListNode(-1); 3162 | ListNode headNode = returnNode; 3163 | 3164 | while (l1 != null && l2 != null) { 3165 | if (l1.val <= l2.val) { 3166 | returnNode.next = l1; 3167 | l1 = l1.next; 3168 | } else { 3169 | returnNode.next = l2; 3170 | l2 = l2.next; 3171 | } 3172 | returnNode = returnNode.next; 3173 | } 3174 | 3175 | if (l1 == null) { 3176 | returnNode.next = l2; 3177 | } else if (l2 == null) { 3178 | returnNode.next = l1; 3179 | } 3180 | 3181 | return headNode.next; 3182 | } 3183 | } 3184 | ``` 3185 | 3186 | 3187 | 3188 | 3189 | 3190 |


3191 | *** 3192 | 3193 | # 22-Generate Parentheses 3194 | 3195 | Given n pairs of parentheses, write a function to generate all combinations of well-formed parentheses. 3196 | 3197 | 3198 | ``` 3199 | For example: 3200 | 3201 | Given n=3, a solution set is: 3202 | 3203 | [ 3204 | "((()))", 3205 | "(()())". 3206 | "(())()", 3207 | "()(())", 3208 | "()()()" 3209 | ] 3210 | ``` 3211 | 3212 | 3213 |

3214 | 3215 | ## Brute Force 3216 | 3217 | **Intuition** 3218 | 3219 | We can generate all 2^(2n) sequences of `(` and `)` characters. Then we can check if each one is valid 3220 | 3221 |
3222 | 3223 | **Algorithm** 3224 | 3225 | To generate all sequences, we use recursion. All sequences of length `n` is just `(` plus all sequences 3226 | of length `n-1`, and then `)` plus all sequences of length `n-1`. 3227 | 3228 | To check whether a sequence is valid, we keep track of `balance`, the net number of opening brackets 3229 | minuts closing brackets. If it falls below zero at any time, or doesn't end in zero, the sequence is 3230 | invalid - otherwise it is valid. 3231 | 3232 | 3233 | ```java 3234 | class Solution { 3235 | 3236 | public List generateParenthesis(int n) { 3237 | 3238 | List combinations = new ArrayList(); 3239 | generateAll(new char[2*n], 0, combinations); 3240 | return combinations; 3241 | } 3242 | 3243 | public void generateAll(char[] current, int pos, List result) { 3244 | 3245 | if(pos == current.length) { 3246 | 3247 | if (valid(current)) { 3248 | result.add(new String(current)); 3249 | } 3250 | 3251 | } else { 3252 | current[pos] = '('; 3253 | generateAll(current, pos+1, result); 3254 | current[pos] = ')'; 3255 | generateAll(current, pos+1, result); 3256 | 3257 | } 3258 | } 3259 | 3260 | public boolean valid(char[] current) { 3261 | 3262 | int balance = 0; 3263 | for (char c : current) { 3264 | 3265 | if(c == '(') { 3266 | balance++; 3267 | } else { 3268 | balance--; 3269 | } 3270 | 3271 | if(balance < 0) { 3272 | return false; 3273 | } 3274 | } 3275 | return (balance == 0); 3276 | } 3277 | } 3278 | ``` 3279 | 3280 | **Complexity Analysis** 3281 | 3282 | ``` 3283 | Time Complexity: O(2^2n * n) For each of 2^2n sequences, we need to create an validate the 3284 | sequence, which takes O(n) work in the worst case 3285 | 3286 | Space Complexity: O(2^2n * n) Naively, every sequence could be valid, see Closure number for 3287 | a tighter asymptotic bound 3288 | ``` 3289 | 3290 | 3291 | 3292 | 3293 |

3294 | 3295 | ## Backtracking 3296 | 3297 | 3298 | **Intuition and Algorithm** 3299 | 3300 | Instead of adding `(` or `)` every time as we do in the Brute Force algorithm, let's only add them 3301 | when we know it will remain a valid sequence. We can do this by keeping track of the number of opening 3302 | and closing brackets we have placed so far. 3303 | 3304 | We can start an opening bracket if we still have one (of `n`) left to place. And we can start a closing 3305 | bracket if it would not exceed the number of opening brackets 3306 | 3307 | 3308 | ```java 3309 | class Solution { 3310 | 3311 | public List generateParenthesis(int n) { 3312 | 3313 | List ans = new ArrayList(); 3314 | backtrack(ans, "", 0, 0, n); 3315 | return ans; 3316 | } 3317 | 3318 | public void backtrack(List ans, String cur, int open, int close, int max){ 3319 | 3320 | if (cur.length() == max*2) { 3321 | ans.add(cur); 3322 | return; 3323 | } 3324 | 3325 | if(open < max) { 3326 | backtrack(ans, cur + "(", open + 1, close, max); 3327 | } 3328 | 3329 | if (close < open) { 3330 | backtrack(ans, cur + ")", open, close +1, max); 3331 | } 3332 | } 3333 | } 3334 | ``` 3335 | 3336 | **Complexity Analysis** 3337 | 3338 | Our complexity analysis rests on understanding how many elements there are in `generateParenthesis(n)`. 3339 | This analysis is outside the scope of this article, but it turns out this is the nth Catalan number 3340 | 1/(n+1) (2n choose n), which is bounded asymptotically by 4^n/(n* sqrt(n)). 3341 | 3342 | ``` 3343 | Time Complexity: O((4^n)/sqrt(n)) Each valid sequence has at most n steps during the 3344 | backtracking procedure 3345 | 3346 | Space Complexity: O((4^n)/sqrt(n)) As described above and using O(n) space to store the 3347 | sequence 3348 | ``` 3349 | 3350 | Another way to think about the runtime of backtracking algorithms on interviewers is O(b^d), where b is 3351 | the branching factor and d is the maximum depth of recursion. 3352 | 3353 | Backtracking is characterized by a number of decisions b that can be made at each level of recursion. 3354 | If you visualize the recursion tree, this is the number of children each internal node has. You can 3355 | also think of b as standing for "base", which helps us remember that b is the base of the exponential. 3356 | 3357 | If we make b decisions at each level of recursion, and we expand the recursion tree to d levels (ie. 3358 | each path has a length of d), then we get b^d nodes. Since backtracking is exhaustive and must visit 3359 | each of these nodes, the runtime is O(b^d) 3360 | 3361 | 3362 | 3363 | 3364 | 3365 | 3366 | 3367 | 3368 |

3369 | 3370 | ## Closure Number 3371 | 3372 | 3373 | 3374 | To enumerate something, generally we would like to express it as a sum of disjoint subsets that are 3375 | easier to count. 3376 | 3377 | 3378 | Consider the *closure number* of a valid parentheses sequence `s`: the least `index >= 0` so that 3379 | `S[0], S[1], ... , S[2 * index + 1] is valid. Clearly, every parentheses sequence has a unique closure 3380 | number. We can try to enumerate them individually. 3381 | 3382 | 3383 |

3384 | 3385 | **Algorithm** 3386 | 3387 | For each closure number c, we know the starting and ending brackets must be at index `0` and 3388 | `2 * c + 1`. Then, the `2 * c` elements between must be a valid sequence, plus the rest of the elements 3389 | must be a valid sequence. 3390 | 3391 | 3392 | 3393 | This is just some minor improvement to the backtracking solution using the fact that for all valid 3394 | solutions the first char is always '(' and the lat char is always ')'. We initialize the starting 3395 | string to '(' and set the recursion bottom condition to string reaching length of `2 * n - 1` - we know 3396 | that we need to append a bracket at the end. There will not be much of an improvement in the runtime 3397 | however. 3398 | 3399 | 3400 | ```java 3401 | class Solution { 3402 | public List generateParenthesis(int n) { 3403 | List ans = new ArrayList(); 3404 | if (n==0) { 3405 | ans.add(""); 3406 | } else { 3407 | for (int c=0; c

3437 | *** 3438 | 3439 | # 23-Merge k Sorted Lists 3440 | 3441 | Merge k sorted linked lists and return it as one sorted list. Analyze and descibe its complexity: 3442 | 3443 | 3444 | ``` 3445 | Example: 3446 | 3447 | Input: 3448 | [ 3449 | 1 -> 4 -> 5, 3450 | 1 -> 3 -> 4, 3451 | 2 -> 6 3452 | ] 3453 | 3454 | Output: 1 -> 1 -> 2 -> 3 -> 4 -> 4 -> 5 -> 6 3455 | ``` 3456 | 3457 | 3458 | 3459 | 3460 | 3461 |

3462 | 3463 | ## Brute Force 3464 | 3465 | 3466 | **Intuition and Algorithm** 3467 | 3468 | * Traverse all the linked lists and collect the values of the nodes into an array 3469 | * Sort and iterate over this array to get the proper value of nodes 3470 | * Create a new sorted linked list and extend it with the new nodes 3471 | 3472 | As for sorting you can refer to the Algorithms/Data Structures CheatSheet for more about sorting algorithms. 3473 | 3474 | 3475 | 3476 | 3477 | 3478 |


3479 | *** 3480 | 3481 | # 146-LRU Cache 3482 | 3483 | Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: `get` and `put`. 3484 | 3485 | `get(key)` - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return `-1` 3486 | 3487 | `put(key, value)` - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item. 3488 | 3489 | **Follow up:** 3490 | Could both of these operations be done in **O(1)** time complexity? 3491 | 3492 | **Example:** 3493 | ``` 3494 | LRUCache cache = new LRUCache(2 /* capacity */); 3495 | 3496 | cache.put(1, 1); 3497 | cache.put(2, 2); 3498 | cache.get(1); // returns 1 3499 | cache.put(3, 3); // evicts key 2 3500 | cache.get(2); // returns -1 (not found) 3501 | 3502 | ``` --------------------------------------------------------------------------------