├── README.md └── src ├── chap01 ├── Q1.java ├── Q2.c ├── Q3.java ├── Q4.java ├── Q5.java ├── Q6.java ├── Q6_2.java ├── Q7.java └── Q8.java ├── chap02 ├── Q1.java ├── Q2.java ├── Q3.java ├── Q4.java ├── Q5.java ├── Q6.java └── Q7.java ├── chap03 ├── Q1.java ├── Q2.java ├── Q3.java ├── Q4.java ├── Q5.java ├── Q6.java └── Q7.java ├── chap04 ├── Q1.java ├── Q2.java ├── Q3.java ├── Q4.java ├── Q5.java ├── Q6.java ├── Q7.java ├── Q8.java └── Q9.java ├── chap05 ├── Q1.java ├── Q2.java ├── Q3.java ├── Q4.txt ├── Q5.java ├── Q6.java ├── Q7.java └── Q8.java ├── chap07 ├── Q1.txt ├── Q2.txt ├── Q3.java ├── Q4.java ├── Q5.java ├── Q6.java └── Q7.java ├── chap08 ├── Q09.java └── Q10.java ├── chap09 ├── Q01.java ├── Q02.java ├── Q03.java ├── Q04.java ├── Q05.java ├── Q06.java ├── Q07.java ├── Q08.java ├── Q09.java ├── Q10.java └── Q11.java ├── chap11 ├── Q1.java ├── Q2.java ├── Q3.java ├── Q4.txt ├── Q5.java ├── Q6.java ├── Q7.java └── Q8.java ├── chap14 └── Q6.java ├── chap17 ├── Q01.java ├── Q02.java ├── Q03.java ├── Q04.java ├── Q04_2.java ├── Q05.java ├── Q06.java ├── Q07.java ├── Q08.java ├── Q09.java ├── Q10.java ├── Q11.java ├── Q12.java ├── Q12_2.java ├── Q13.java └── Q14.java ├── chap18 ├── Q01.java ├── Q02.java ├── Q03.java ├── Q04.java ├── Q05.java ├── Q06.java ├── Q07.java ├── Q07_2.java ├── Q08.java ├── Q09.java ├── Q10.java ├── Q11.java ├── Q12.java └── Q13.java └── helpers ├── Bit.java ├── GraphNode.java ├── LinkedListNode.java ├── Printer.java ├── TreeNode.java └── Trie.java /README.md: -------------------------------------------------------------------------------- 1 | # cracking-the-coding-interview 2 | 3 | My Java solutions to the questions in Cracking the Coding Interview (5th Edition) =) 4 | -------------------------------------------------------------------------------- /src/chap01/Q1.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | /** 4 | * Implement an algorithm to determine if a string has all unique characters. What 5 | * if you cannot use additional data structures? (Assume string is ASCII based.) 6 | */ 7 | public class Q1 { 8 | // use boolean array 9 | boolean hasUniqueChars(String str) { 10 | if (str == null || str.isEmpty()) return false; 11 | if (str.length() > 256) return false; 12 | 13 | boolean[] charSet = new boolean[256]; 14 | for (int i = 0; i < str.length(); ++i) { 15 | char ch = str.charAt(i); 16 | if (charSet[ch]) return false; 17 | else charSet[ch] = true; 18 | } 19 | return true; 20 | } 21 | 22 | // use bit vector 23 | boolean hasUniqueChars2(String str) { 24 | if (str == null || str.isEmpty()) return false; 25 | if (str.length() > 256) return false; 26 | 27 | int bitVector = 0; 28 | for (int i = 0; i < str.length(); ++i) { 29 | char ch = str.charAt(i); 30 | if ((bitVector & (1 << ch)) > 0) return false; 31 | else bitVector |= (1 << ch); 32 | } 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/chap01/Q2.c: -------------------------------------------------------------------------------- 1 | // Implement a function void reverse(char* str) in C 2 | // or C++ which reverses a null terminated string. 3 | void reverse(char* str) { 4 | if (str == NULL) return; 5 | 6 | char* end = str; 7 | while (*end) { 8 | ++end; 9 | } 10 | --end; 11 | 12 | char tmp; 13 | while (str < end) { 14 | tmp = *str; 15 | *str = *end; 16 | *end = tmp; 17 | ++str; 18 | --end; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/chap01/Q3.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | import java.util.Arrays; 4 | 5 | /** 6 | * Given two strings, write a method to decide if one is a permutation of the other. 7 | * (Assume comparison is case-sensitive, space-significant, ASCII-based.) 8 | */ 9 | public class Q3 { 10 | boolean isPermutation(String s1, String s2) { 11 | if (s1 == null && s2 == null) return true; 12 | if (s1 == null || s2 == null) return false; 13 | if (s1.length() != s2.length()) return false; 14 | 15 | int[] charCount = new int[256]; 16 | for (int i = 0; i < s1.length(); ++i) { 17 | ++charCount[s1.charAt(i)]; 18 | } 19 | 20 | for (int i = 0; i < s2.length(); ++i) { 21 | if (--charCount[s2.charAt(i)] < 0) 22 | return false; 23 | } 24 | return true; 25 | } 26 | 27 | boolean isPermutation2(String s1, String s2) { 28 | if (s1 == null && s2 == null) return true; 29 | if (s1 == null || s2 == null) return false; 30 | if (s1.length() != s2.length()) return false; 31 | 32 | char[] charArray1 = s1.toCharArray(); 33 | char[] charArray2 = s2.toCharArray(); 34 | Arrays.sort(charArray1); 35 | Arrays.sort(charArray2); 36 | return new String(charArray1).equals(new String(charArray2)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/chap01/Q4.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write a method to replace all spaces in a string with'%20'. You may assume that 7 | * the string has sufficient space at the end of the string to hold the additional 8 | * characters, and that you are given the "true" length of the string. (Note: if 9 | * implementing in Java, please use a character array so that you can perform this 10 | * operation in place.) 11 | * EXAMPLE 12 | * Input: "Mr John Smith " 13 | * Output: "Mr%20John%20Smith" 14 | */ 15 | public class Q4 { 16 | static void replaceSpaces(char[] str, int length) { 17 | // 1st scan: count spaces 18 | int cnt = 0; 19 | for (char ch : str) { 20 | if (ch == ' ') ++cnt; 21 | } 22 | 23 | // 2nd scan: replace spaces 24 | int p = length + 2 * cnt; 25 | str[p] = '\0'; //XXX 26 | --p; 27 | for (int i = length - 1; i >= 0; --i) { 28 | if (str[i] == ' ') { 29 | str[p--] = '0'; 30 | str[p--] = '2'; 31 | str[p--] = '%'; 32 | } else { 33 | str[p--] = str[i]; 34 | } 35 | } 36 | } 37 | 38 | //TEST---------------------------------- 39 | public static void main(String[] args) { 40 | char[] str = {'a','b',' ','c',' ','d','\0','\0','\0','\0','\0','\0','\0'}; 41 | replaceSpaces(str, 6); 42 | printArray(str); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/chap01/Q5.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Implement a method to perform basic string compression using the counts of 7 | * repeated characters. For example, the string aabcccccaaa would become 8 | * a2blc5a3. If the "compressed" string would not become smaller than the original 9 | * string, your method should return the original string. 10 | */ 11 | public class Q5 { 12 | static String compress(String s) { 13 | if (s == null || s.isEmpty()) return s; 14 | 15 | char prev = s.charAt(0); 16 | int cnt = 1; 17 | StringBuffer sb = new StringBuffer(); 18 | sb.append(prev); 19 | for (int i = 1; i < s.length(); ++i) { 20 | char curr = s.charAt(i); 21 | if (curr == prev) { 22 | ++cnt; 23 | } else { 24 | prev = curr; 25 | sb.append(cnt) 26 | .append(curr); 27 | cnt = 1; 28 | } 29 | } 30 | sb.append(cnt); 31 | 32 | return sb.toString().length() >= s.length() ? s : sb.toString(); 33 | } 34 | 35 | //TEST---------------------------------- 36 | public static void main(String[] args) { 37 | println(compress("aabcccccaaa")); 38 | println(compress("aabbcc")); 39 | println(compress("aaaaaaaaaaaaaaaaaaaaa")); 40 | println(compress("abcdefg")); 41 | println(compress("a")); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/chap01/Q6.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given an image represented by an NxN matrix, where each pixel in 7 | * the image is 4 bytes, write a method to rotate the image by 90 8 | * degrees. Can you do this in place? 9 | */ 10 | public class Q6 { 11 | // With extra space. 12 | static int[][] rotate(int[][] matrix) { 13 | int n = matrix.length; 14 | int[][] ret = new int[n][n]; 15 | for (int i = 0; i < n; ++i) { 16 | for (int j = 0; j < n; ++j) { 17 | ret[i][j] = matrix[n-1-j][i]; 18 | } 19 | } 20 | return ret; 21 | } 22 | 23 | // In place. 24 | // Relation matrix[i][j] = matrix[n-1-j][i] holds. 25 | static void rotateInPlace(int[][] matrix) { 26 | int n = matrix.length; 27 | for (int i = 0; i < n/2; ++i) { 28 | for (int j = i; j < n-1-i; ++j) { 29 | // save top 30 | int tmp = matrix[i][j]; 31 | // left to top 32 | matrix[i][j] = matrix[n-1-j][i]; 33 | // bottom to left 34 | matrix[n-1-j][i] = matrix[n-1-i][n-1-j]; 35 | // right to bottom 36 | matrix[n-1-i][n-1-j] = matrix[j][n-1-i]; 37 | // top to right 38 | matrix[j][n-1-i] = tmp; 39 | } 40 | } 41 | } 42 | 43 | //TEST---------------------------------- 44 | public static void main(String[] args) { 45 | int[][] a = {{1, 2, 3, 4, 5}, 46 | {11,22,33,44,55}, 47 | {5, 4, 3, 2, 1}, 48 | {55,44,33,22,11}, 49 | {6, 7, 8, 9, 0}}; 50 | printArray(rotate(a)); 51 | println(); 52 | rotateInPlace(a); 53 | printArray(a); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/chap01/Q6_2.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | import static helpers.Printer.*; 4 | 5 | public class Q6_2 { 6 | 7 | static void rotateCounterclockwiseInPlace(int[][] matrix, int n) { 8 | for (int layer = 0; layer < n/2; ++layer) { 9 | for (int i = layer; i < n - 1 - layer; ++i) { 10 | // save top 11 | int tmp = matrix[layer][i]; 12 | // right to top 13 | matrix[layer][i] = matrix[i][n - 1 - layer]; 14 | // bottom to right 15 | matrix[i][n - 1 - layer] = matrix[n - 1 - layer][n - 1 - i]; 16 | // left to bottom 17 | matrix[n - 1 - layer][n - 1- i] = matrix[n - 1 - i][layer]; 18 | // top to left 19 | matrix[n - 1 - i][layer] = tmp; 20 | } 21 | } 22 | } 23 | 24 | static void mirrorNWSE(int[][] matrix, int n) { 25 | for (int i = 0; i < n; ++i) { 26 | for (int j = i; j < n; ++j) { 27 | int tmp = matrix[i][j]; 28 | matrix[i][j] = matrix[j][i]; 29 | matrix[j][i] = tmp; 30 | } 31 | } 32 | } 33 | 34 | static void mirrorNESW(int[][] matrix, int n) { 35 | for (int i = 0; i < n; ++i) { 36 | for (int j = 0; j < n - i; ++j) { 37 | int tmp = matrix[i][j]; 38 | matrix[i][j] = matrix[n - 1 - j][n - 1 - i]; 39 | matrix[n - 1 - j][n - 1 - i] = tmp; 40 | } 41 | } 42 | } 43 | 44 | static void mirrorHorizontal(int[][] matrix, int n) { 45 | for (int i = 0; i < n; ++i) { 46 | for (int j = 0; j < n/2; ++j) { 47 | int tmp = matrix[i][j]; 48 | matrix[i][j] = matrix[i][n - 1 - j]; 49 | matrix[i][n - 1 - j] = tmp; 50 | } 51 | } 52 | } 53 | 54 | static void mirrorVertical(int[][] matrix, int n) { 55 | for (int i = 0; i < n/2; ++i) { 56 | for (int j = 0; j < n; ++j) { 57 | int tmp = matrix[i][j]; 58 | matrix[i][j] = matrix[n - 1 - i][j]; 59 | matrix[n - 1 - i][j] = tmp; 60 | } 61 | } 62 | } 63 | 64 | //TEST---------------------------------- 65 | public static void main(String[] args) { 66 | int[][] a = {{1, 2, 3, 4, 5}, 67 | {11,22,33,44,55}, 68 | {5, 4, 3, 2, 1}, 69 | {55,44,33,22,11}, 70 | {6, 7, 8, 9, 0}}; 71 | 72 | rotateCounterclockwiseInPlace(a, 5); 73 | printArray(a); 74 | println(); 75 | resetArray(a); 76 | 77 | mirrorNWSE(a, 5); 78 | printArray(a); 79 | println(); 80 | resetArray(a); 81 | 82 | mirrorNESW(a, 5); 83 | printArray(a); 84 | println(); 85 | resetArray(a); 86 | 87 | mirrorHorizontal(a, 5); 88 | printArray(a); 89 | println(); 90 | resetArray(a); 91 | 92 | mirrorVertical(a, 5); 93 | printArray(a); 94 | println(); 95 | resetArray(a); 96 | } 97 | 98 | private static void printArray(int[][] a) { 99 | for (int[] row : a) { 100 | for (int col : row) { 101 | print(col + " "); 102 | } 103 | println(); 104 | } 105 | } 106 | 107 | private static void resetArray(int[][] a) { 108 | a[0][0]=1; a[0][1]=2; a[0][2]=3; a[0][3]=4; a[0][4]=5; 109 | a[1][0]=11;a[1][1]=22;a[1][2]=33;a[1][3]=44;a[1][4]=55; 110 | a[2][0]=5; a[2][1]=4; a[2][2]=3; a[2][3]=2; a[2][4]=1; 111 | a[3][0]=55;a[3][1]=44;a[3][2]=33;a[3][3]=22;a[3][4]=11; 112 | a[4][0]=6; a[4][1]=7; a[4][2]=8; a[4][3]=9; a[4][4]=0; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/chap01/Q7.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write an algorithm such that if an element in an MxN matrix is 0, 7 | * its entire row and column are set to 0. 8 | */ 9 | public class Q7 { 10 | // use boolean array 11 | static void setZeros(int[][] matrix) { 12 | boolean[] rows = new boolean[matrix.length]; 13 | boolean[] cols = new boolean[matrix[0].length]; 14 | 15 | // mark zero 16 | for (int i = 0; i < matrix.length; ++i) { 17 | for (int j = 0; j < matrix[0].length; ++j) { 18 | if (matrix[i][j] == 0) { 19 | rows[i] = cols[j] = true; 20 | } 21 | } 22 | } 23 | 24 | // set zeros 25 | for (int i = 0; i < matrix.length; ++i) { 26 | for (int j = 0; j < matrix[0].length; ++j) { 27 | if (rows[i] || cols[j]) { 28 | matrix[i][j] = 0; 29 | } 30 | } 31 | } 32 | } 33 | 34 | // use bit vector 35 | static void setZeros2(int[][] matrix) { 36 | long bitVecRows = 0; 37 | long bitVecCols = 0; 38 | 39 | // mark zero 40 | for (int i = 0; i < matrix.length; ++i) { 41 | for (int j = 0; j < matrix[0].length; ++j) { 42 | if (matrix[i][j] == 0) { 43 | bitVecRows |= 1 << i; 44 | bitVecCols |= 1 << j; 45 | } 46 | } 47 | } 48 | 49 | // set zeros 50 | for (int i = 0; i < matrix.length; ++i) { 51 | for (int j = 0; j < matrix[0].length; ++j) { 52 | if ((bitVecRows & (1 << i)) != 0 || (bitVecCols & (1 << j)) != 0) { 53 | matrix[i][j] = 0; 54 | } 55 | } 56 | } 57 | } 58 | 59 | //TEST---------------------------------- 60 | public static void main(String[] args) { 61 | int[][] a = {{0,2,3,4,5}, 62 | {1,2,3,4,5}, 63 | {5,4,3,0,1}, 64 | {5,4,3,2,1}, 65 | {6,7,8,9,0}}; 66 | setZeros2(a); 67 | printArray(a); 68 | } 69 | 70 | private static void printArray(int[][] a) { 71 | for (int[] row : a) { 72 | for (int col : row) { 73 | print(col + " "); 74 | } 75 | println(); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/chap01/Q8.java: -------------------------------------------------------------------------------- 1 | package chap01; 2 | 3 | /** 4 | * Assume you have a method isSubstring which checks if one word is a 5 | * substring of another. Given two strings, si and s2, write code to check if s2 is 6 | * a rotation of si using only one call to isSubstring (e.g.,"waterbottle" is a rotation 7 | * of "erbottlewat"). 8 | * (Assume an empty string is a rotation of an empty string.) 9 | */ 10 | public class Q8 { 11 | boolean isRotation(String s1, String s2) { 12 | if (s1 == null || s2 == null) return false; 13 | if (s1.length() != s2.length()) return false; 14 | return isSubstring(s1 + s1, s2); 15 | } 16 | 17 | private boolean isSubstring(String s1, String s2) { 18 | return s1.contains(s2); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/chap02/Q1.java: -------------------------------------------------------------------------------- 1 | package chap02; 2 | 3 | import java.util.HashSet; 4 | 5 | import helpers.LinkedListNode; 6 | 7 | /** 8 | * Write code to remove duplicates from an unsorted linked list. 9 | * 10 | * FOLLOW UP 11 | * How would you solve this problem if a temporary buffer is not allowed? 12 | */ 13 | public class Q1 { 14 | // with extra space 15 | static void removeDuplicates(LinkedListNode n) { 16 | HashSet set = new HashSet(); 17 | LinkedListNode prev = null; 18 | while (n != null) { 19 | if (set.contains(n.data)) { 20 | prev.next = n.next; 21 | } 22 | else { 23 | set.add(n.data); 24 | prev = n; 25 | } 26 | n = n.next; 27 | } 28 | } 29 | 30 | //without extra space 31 | static void removeDuplicates2(LinkedListNode n) { 32 | while (n != null) { 33 | LinkedListNode runner = n; 34 | while (runner.next != null) { 35 | if (runner.next.data == n.data) { 36 | runner.next = runner.next.next; 37 | } else { 38 | runner = runner.next; 39 | } 40 | } 41 | n = n.next; 42 | } 43 | } 44 | 45 | //TEST---------------------------------- 46 | public static void main(String[] args) { 47 | int[] list = {1,1,2,3,3,4,2,5,5}; 48 | LinkedListNode n = LinkedListNode.buildList(list); 49 | removeDuplicates(n); 50 | LinkedListNode.printList(n); 51 | n = LinkedListNode.buildList(list); 52 | removeDuplicates2(n); 53 | LinkedListNode.printList(n); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/chap02/Q2.java: -------------------------------------------------------------------------------- 1 | package chap02; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.LinkedListNode; 6 | 7 | /** 8 | * Implement an algorithm to find the kth to last element of a singly linked list. 9 | */ 10 | public class Q2 { 11 | //Returns nearest node if index out of bounds. 12 | static LinkedListNode nthToLast(LinkedListNode head, int k) { 13 | LinkedListNode n = head, r = head; 14 | for (int i = 0; i < k; ++i) { 15 | r = r.next; 16 | if (r == null) return n; 17 | } 18 | while (r.next != null) { 19 | r = r.next; 20 | n = n.next; 21 | } 22 | return n; 23 | } 24 | 25 | //TEST---------------------------------- 26 | public static void main(String[] args) { 27 | int[] list = {5,4,3,2,1,0}; 28 | LinkedListNode n = LinkedListNode.buildList(list); 29 | println(nthToLast(n, 0)); 30 | println(nthToLast(n, 3)); 31 | println(nthToLast(n, 5)); 32 | println(nthToLast(n, 6)); 33 | println(nthToLast(n, -100)); 34 | println(nthToLast(n, 100)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/chap02/Q3.java: -------------------------------------------------------------------------------- 1 | package chap02; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.LinkedListNode; 6 | 7 | /** 8 | * Implement an algorithm to delete a node in the middle of a singly linked list, 9 | * given only access to that node. 10 | */ 11 | public class Q3 { 12 | static boolean deleteNode(LinkedListNode n) { 13 | //XXX: fail if the node is the last element. 14 | if (n == null || n.next == null) return false; 15 | n.data = n.next.data; 16 | n.next = n.next.next; 17 | return true; 18 | } 19 | 20 | //TEST---------------------------------- 21 | public static void main(String[] args) { 22 | int[] list = {3,2,1,0}; 23 | LinkedListNode head = LinkedListNode.buildList(list); 24 | LinkedListNode n1 = head.next, 25 | n2 = head.next.next.next, 26 | n3 = null; 27 | println("DELETE " + n3 + ": " + deleteNode(n3)); 28 | LinkedListNode.printList(n3); 29 | println("DELETE " + n2 + ": " + deleteNode(n2)); 30 | LinkedListNode.printList(n2); 31 | println("DELETE " + n1 + ": " + deleteNode(n1)); 32 | LinkedListNode.printList(n1); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/chap02/Q4.java: -------------------------------------------------------------------------------- 1 | package chap02; 2 | 3 | import helpers.LinkedListNode; 4 | 5 | /** 6 | * Write code to partition a linked list around a value x, such that all 7 | * nodes less than x come before all nodes greater than or equal to x. 8 | */ 9 | public class Q4 { 10 | static LinkedListNode partition(LinkedListNode n, int x) { 11 | LinkedListNode head1 = null, tail1 = null, 12 | head2 = null, tail2 = null; 13 | while (n != null) { 14 | if (n.data < x) { 15 | if (head1 == null) { 16 | head1 = tail1 = n; 17 | } else { 18 | tail1.next = n; 19 | tail1 = n; 20 | } 21 | } else { 22 | if (head2 == null) { 23 | head2 = tail2 = n; 24 | } else { 25 | tail2.next = n; 26 | tail2 = n; 27 | } 28 | } 29 | n = n.next; 30 | } 31 | // Trim tails 32 | if (tail1 != null) tail1.next = null; 33 | if (tail2 != null) tail2.next = null; 34 | 35 | // List1 is empty 36 | if (head1 == null) return head2; 37 | tail1.next = head2; 38 | return head1; 39 | } 40 | 41 | //TEST---------------------------------- 42 | public static void main(String[] args) { 43 | int[] list = {9,2,7,4,6,5,3,8,1}; 44 | LinkedListNode n = LinkedListNode.buildList(list); 45 | n = LinkedListNode.buildList(list); 46 | LinkedListNode.printList(partition(n, 6)); 47 | n = LinkedListNode.buildList(list); 48 | LinkedListNode.printList(partition(n, 0)); 49 | n = LinkedListNode.buildList(list); 50 | LinkedListNode.printList(partition(n, 100)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/chap02/Q5.java: -------------------------------------------------------------------------------- 1 | package chap02; 2 | 3 | import helpers.LinkedListNode; 4 | 5 | /** 6 | * You have two numbers represented by a linked list, where each node contains a 7 | * single digit. The digits are stored in reverse order, such that the 1 's digit 8 | * is at the head of the list. Write a function that adds the two numbers and 9 | * returns the sum as a linked list. 10 | */ 11 | public class Q5 { 12 | static LinkedListNode addLists(LinkedListNode n1, LinkedListNode n2) { 13 | LinkedListNode n = new LinkedListNode(-1); 14 | LinkedListNode head = n; 15 | int carry = 0; 16 | while (n1 != null || n2 != null || carry != 0) { 17 | int sum = 0; 18 | if (n1 != null) { 19 | sum += n1.data; 20 | n1 = n1.next; 21 | } 22 | if (n2 != null) { 23 | sum += n2.data; 24 | n2 = n2.next; 25 | } 26 | if (carry != 0) { 27 | sum += carry; 28 | } 29 | int digit = sum % 10; 30 | carry = sum / 10; 31 | n.next = new LinkedListNode(digit); 32 | n = n.next; 33 | } 34 | return head.next; 35 | } 36 | 37 | //TEST---------------------------------- 38 | public static void main(String[] args) { 39 | LinkedListNode l1 = LinkedListNode.buildList(new int[] {2,1,8}); 40 | LinkedListNode l2 = LinkedListNode.buildList(new int[] {8,8,1}); 41 | LinkedListNode.printList(addLists(l1, l2)); 42 | 43 | l1 = LinkedListNode.buildList(new int[] {2,9,1}); 44 | l2 = LinkedListNode.buildList(new int[] {8}); 45 | LinkedListNode.printList(addLists(l1, l2)); 46 | LinkedListNode.printList(addLists(l2, l1)); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/chap02/Q6.java: -------------------------------------------------------------------------------- 1 | package chap02; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.LinkedListNode; 6 | 7 | /** 8 | * Given a circular linked list, implement an algorithm which returns 9 | * the node at the beginning of the loop. 10 | */ 11 | public class Q6 { 12 | static LinkedListNode findBeginning(LinkedListNode head) { 13 | LinkedListNode fast = head, slow = head; 14 | while (fast != null && fast.next != null) { 15 | fast = fast.next.next; 16 | slow = slow.next; 17 | if (fast == slow) break; 18 | } 19 | if (fast == null || fast.next == null) return null; 20 | fast = head; 21 | while (fast != slow) { 22 | fast = fast.next; 23 | slow = slow.next; 24 | } 25 | return fast; 26 | } 27 | 28 | //TEST---------------------------------- 29 | public static void main(String[] args) { 30 | int[] list = {1,2,3,4,5,6}; 31 | LinkedListNode n = LinkedListNode.buildList(list), head = n; 32 | println(findBeginning(head)); 33 | 34 | while (n.next != null) n = n.next; 35 | n.next = head.next.next.next; 36 | println(findBeginning(head)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/chap02/Q7.java: -------------------------------------------------------------------------------- 1 | package chap02; 2 | 3 | import static helpers.Printer.*; 4 | import java.util.Stack; 5 | 6 | import helpers.LinkedListNode; 7 | 8 | /** 9 | * Implement a function to check if a linked list is 10 | * a palindrome (like 0->1->2->1->0). 11 | */ 12 | public class Q7 { 13 | static boolean isPalindrome(LinkedListNode head) { 14 | if (head == null) return false; 15 | LinkedListNode p1 = head, p2 = head; 16 | Stack s = new Stack(); 17 | while (p2 != null && p2.next != null) { 18 | s.push(p1.data); 19 | p1 = p1.next; 20 | p2 = p2.next.next; 21 | } 22 | // handle odd nodes 23 | if (p2 != null) p1 = p1.next; 24 | while (p1 != null) { 25 | if(p1.data != s.pop()) return false; 26 | p1 = p1.next; 27 | } 28 | return true; 29 | } 30 | 31 | //TEST---------------------------------- 32 | public static void main(String[] args) { 33 | println(isPalindrome(null)); 34 | println(isPalindrome(LinkedListNode.buildList(new int[] {1}))); 35 | println(isPalindrome(LinkedListNode.buildList(new int[] {1,1}))); 36 | println(isPalindrome(LinkedListNode.buildList(new int[] {1,2,3,4,4,3,2,1}))); 37 | println(isPalindrome(LinkedListNode.buildList(new int[] {1,2,3,4,4,3,3,2,1}))); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/chap03/Q1.java: -------------------------------------------------------------------------------- 1 | package chap03; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Arrays; 6 | 7 | /** 8 | * Describe how you could use a single array to implement three stacks. 9 | */ 10 | public class Q1 { 11 | private static final int STACK_SIZE = 50; 12 | private static final int STACK_NUM = 3; 13 | 14 | private static int[] stackPointers = new int[STACK_NUM]; 15 | static { Arrays.fill(stackPointers, -1); } 16 | private int[] buffer = new int[STACK_SIZE * STACK_NUM]; 17 | 18 | public void push(int stackNum, int item) { 19 | if (isFull(stackNum)) 20 | throw new IllegalArgumentException("Stack " + stackNum + " is full!"); 21 | ++stackPointers[stackNum]; 22 | buffer[getBufferIndex(stackNum)] = item; 23 | } 24 | 25 | public int pop(int stackNum) { 26 | int val = peek(stackNum); 27 | --stackPointers[stackNum]; 28 | return val; 29 | } 30 | 31 | public int peek(int stackNum) { 32 | if (isEmpty(stackNum)) 33 | throw new IllegalArgumentException("Stack " + stackNum + " is empty!"); 34 | return buffer[getBufferIndex(stackNum)]; 35 | } 36 | 37 | public boolean isFull(int stackNum) { 38 | if (stackNum < 0 || stackNum >= STACK_NUM) 39 | throw new IllegalArgumentException("Stack " + stackNum + " doen't exist!"); 40 | return stackPointers[stackNum] >= STACK_SIZE - 1; 41 | } 42 | 43 | public boolean isEmpty(int stackNum) { 44 | if (stackNum < 0 || stackNum >= STACK_NUM) 45 | throw new IllegalArgumentException("Stack " + stackNum + " doen't exist!"); 46 | return stackPointers[stackNum] <= -1; 47 | } 48 | 49 | public void printStack(int stackNum) { 50 | if (stackNum < 0 || stackNum >= STACK_NUM) 51 | throw new IllegalArgumentException("Stack " + stackNum + " doen't exist!"); 52 | int top = getBufferIndex(stackNum); 53 | int btm = stackNum * STACK_SIZE; 54 | print("Stack " + stackNum + ": "); 55 | for (int i = btm; i <= top; ++i) { 56 | print(buffer[i] + " "); 57 | } 58 | println("[TOP]"); 59 | } 60 | 61 | public void printStacks() { 62 | for (int i = 0; i < STACK_NUM; ++i) { 63 | printStack(i); 64 | } 65 | } 66 | 67 | private int getBufferIndex(int stackNum) { 68 | return stackPointers[stackNum] + stackNum * STACK_SIZE; 69 | } 70 | 71 | //TEST---------------------------------- 72 | public static void main(String[] args) { 73 | Q1 stack = new Q1(); 74 | stack.printStacks(); 75 | println(); 76 | stack.push(0, -1); stack.push(0, -2); stack.push(0, -3); 77 | stack.push(1, 1); stack.push(1, 2); stack.push(1, 3); 78 | stack.push(2, 10); stack.push(2, 20); stack.push(2, 30); stack.push(2, 40); 79 | stack.printStacks(); 80 | println(); 81 | println("Pop Stack 0: " + stack.pop(0)); 82 | println("Pop Stack 1: " + stack.pop(1)); 83 | println("Pop Stack 1: " + stack.pop(1)); 84 | println("Pop Stack 2: " + stack.pop(2)); 85 | println(); 86 | stack.printStacks(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/chap03/Q2.java: -------------------------------------------------------------------------------- 1 | package chap03; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Stack; 6 | 7 | /** 8 | * How would you design a stack which, in addition to push 9 | * and pop, also has a function min which returns the minimum 10 | * element? Push, pop and min should all operate in O(1) time. 11 | */ 12 | @SuppressWarnings("serial") 13 | public class Q2 /* MinStack */ extends Stack { 14 | private Stack min = new Stack(); 15 | 16 | public void push(int item) { 17 | if (min.isEmpty() || item < min()) { 18 | min.push(item); 19 | } 20 | super.push(item); 21 | } 22 | 23 | public Integer pop() { 24 | int item = super.pop(); 25 | if (item == min()) { 26 | min.pop(); 27 | } 28 | return item; 29 | } 30 | 31 | public Integer min() { 32 | return min.peek(); 33 | } 34 | 35 | //TEST---------------------------------- 36 | public static void main(String[] args) { 37 | Q2 stack = new Q2(); 38 | stack.push(2); println(stack.min()); 39 | stack.push(-1); println(stack.min()); 40 | stack.push(3); println(stack.min()); 41 | stack.push(-10); println(stack.min()); 42 | stack.pop(); println(stack.min()); 43 | stack.pop(); println(stack.min()); 44 | stack.push(-20); println(stack.min()); 45 | stack.pop(); println(stack.min()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/chap03/Q3.java: -------------------------------------------------------------------------------- 1 | package chap03; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.LinkedList; 6 | import java.util.Stack; 7 | 8 | /** 9 | * Imagine a (literal) stack of plates. If the stack gets too high, it 10 | * might topple. Therefore, in real life, we would likely start a new 11 | * stack when the previous stack exceeds some threshold. Implement a 12 | * data structure SetOfStacks that mimics this. SetOfStacks should be 13 | * composed of several stacks and should create a new stack once the 14 | * previous one exceeds capacity. SetOfStacks.push() and SetOfStacks.pop() 15 | * should behave identically to a single stack (that is, pop() should 16 | * return the same values as it would if there were just a single stack). 17 | * 18 | * FOLLOW UP 19 | * Implement a function popAt(int index) which performs a pop operation 20 | * on a specific sub-stack. 21 | */ 22 | public class Q3 { 23 | private static final int STACK_SIZE = 3; 24 | private LinkedList> stacks = new LinkedList>(); 25 | 26 | public void push(int item) { 27 | if (stacks.isEmpty() || stacks.getLast().size() >= STACK_SIZE) { 28 | Stack stack = new Stack(); 29 | stack.push(item); 30 | stacks.add(stack); 31 | } else { 32 | stacks.getLast().push(item); 33 | } 34 | } 35 | 36 | public Integer pop() { 37 | if (stacks.isEmpty()) 38 | throw new IllegalStateException("Stacks are empty!"); 39 | Stack last = stacks.getLast(); 40 | int item = last.pop(); 41 | if (last.isEmpty()) 42 | stacks.removeLast(); 43 | return item; 44 | } 45 | 46 | public Integer popAt(int index) { 47 | if (stacks.isEmpty()) 48 | throw new IllegalStateException("Stacks are empty!"); 49 | if (index < 0 || index >= stacks.size()) 50 | throw new IllegalArgumentException("Invalid index!"); 51 | int item = stacks.get(index).pop(); 52 | for (int i = index; i < stacks.size() - 1; ++i) { 53 | Stack curr = stacks.get(i); 54 | Stack next = stacks.get(i + 1); 55 | curr.push(next.remove(0)); 56 | } 57 | if (stacks.getLast().isEmpty()) 58 | stacks.removeLast(); 59 | return item; 60 | } 61 | 62 | public void printStacks() { 63 | for (Stack stack : stacks) { 64 | for (int item : stack) 65 | print(item + " "); 66 | println("[TOP]"); 67 | } 68 | } 69 | 70 | //TEST---------------------------------- 71 | public static void main(String[] args) { 72 | Q3 setOfStacks = new Q3(); 73 | setOfStacks.push(1); setOfStacks.push(2); setOfStacks.push(3); 74 | setOfStacks.push(4); setOfStacks.push(5); setOfStacks.push(6); 75 | setOfStacks.push(7); setOfStacks.push(8); setOfStacks.push(9); 76 | setOfStacks.printStacks(); 77 | println(); 78 | setOfStacks.popAt(1); 79 | setOfStacks.popAt(0); 80 | setOfStacks.printStacks(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/chap03/Q4.java: -------------------------------------------------------------------------------- 1 | package chap03; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Stack; 6 | 7 | /** 8 | * In the classic problem of the Towers of Hanoi, you have 3 towers and N disks 9 | * of different sizes which can slide onto any tower. The puzzle starts with disks sorted 10 | * disks sorted in ascending order of size from top to bottom (i.e., each disk sits on top 11 | * of an even larger one). You have the following constraints: 12 | * (1) Only one disk can be moved at a time. 13 | * (2) A disk is slid off the top of one tower onto the next tower. 14 | * (3) A disk can only be placed on top of a larger disk. 15 | * Write a program to move the disks from the first tower to the last using stacks. 16 | */ 17 | public class Q4 { 18 | static class Tower { 19 | Stack disks; 20 | int id; 21 | 22 | public Tower(int id) { 23 | this.id = id; 24 | this.disks = new Stack(); 25 | } 26 | 27 | public void printTower() { 28 | for (int disk : disks) print(disk + " "); 29 | println("[TOP]"); 30 | } 31 | } 32 | 33 | public static void moveTop(Tower from, Tower to) { 34 | if (to.disks.isEmpty() || from.disks.peek() < to.disks.peek()) { 35 | printfln("Move disk %d from tower %d to tower %d", 36 | from.disks.peek(), from.id, to.id); 37 | to.disks.push(from.disks.pop()); 38 | } else { 39 | printfln("Unable to move disk %d on top of smaller disk %d from tower %d to tower %d", 40 | from.disks.peek(), to.disks.peek(), from.id, to.id); 41 | } 42 | } 43 | 44 | public static void moveDisks(int n, Tower from, Tower to, Tower buffer) { 45 | if (n <= 0) return; 46 | moveDisks(n - 1, from, buffer, to); 47 | moveTop(from, to); 48 | moveDisks(n - 1, buffer, to, from); 49 | } 50 | 51 | public static void printTowers(Tower[] towers) { 52 | for (Tower t : towers) { 53 | print("Tower " + t.id + ": "); 54 | t.printTower(); 55 | } 56 | } 57 | 58 | //TEST---------------------------------- 59 | public static void main(String[] args) { 60 | final int DISKS_SIZE = 5; 61 | Tower[] towers = new Tower[3]; 62 | for (int i = 0; i < towers.length; ++i) 63 | towers[i] = new Tower(i + 1); 64 | for (int i = DISKS_SIZE; i > 0; --i) 65 | towers[0].disks.push(i); 66 | println("BEFORE ---------------------"); 67 | printTowers(towers); 68 | println("\nMOVING ---------------------"); 69 | moveDisks(DISKS_SIZE, towers[0], towers[2], towers[1]); 70 | println("\nAFTER ----------------------"); 71 | printTowers(towers); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/chap03/Q5.java: -------------------------------------------------------------------------------- 1 | package chap03; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Stack; 6 | 7 | /** 8 | * Implement a MyQueue class which implements a queue using two stacks. 9 | */ 10 | public class Q5 { 11 | private static final int LOAD_FACTOR = 10; 12 | private Stack head = new Stack(); 13 | private Stack tail = new Stack(); 14 | 15 | public void enqueue(int item) { 16 | rebalance(); 17 | tail.push(item); 18 | } 19 | 20 | public int dequeue() { 21 | rebalance(); 22 | if (head.isEmpty()) 23 | throw new IllegalStateException("Queue is empty!"); 24 | return head.pop(); 25 | } 26 | 27 | public int peekHead() { 28 | if (head.isEmpty()) 29 | throw new IllegalStateException("Queue is empty!"); 30 | return head.peek(); 31 | } 32 | 33 | public int peekTail() { 34 | if (head.isEmpty()) 35 | throw new IllegalStateException("Queue is empty!"); 36 | return tail.peek(); 37 | } 38 | 39 | public int size() { 40 | return head.size() + tail.size(); 41 | } 42 | 43 | public void rebalance() { 44 | if (tail.size() >= LOAD_FACTOR && 45 | tail.size() >= 2 * head.size() || 46 | head.isEmpty()) { 47 | while (!tail.isEmpty() ) { 48 | head.push(tail.pop()); 49 | } 50 | } 51 | } 52 | 53 | public void printQueue() { 54 | printQueue(true); 55 | } 56 | 57 | public void printQueue(boolean showBoundary) { 58 | print("[HEAD] "); 59 | for (int i = head.size() - 1; i >= 0; --i) 60 | print(head.get(i) + " "); 61 | if (showBoundary) 62 | print("| "); 63 | for (int item : tail) 64 | print(item + " "); 65 | println("[TAIL]"); 66 | println(); 67 | } 68 | 69 | //TEST---------------------------------- 70 | public static void main(String[] args) { 71 | Q5 myQueue = new Q5(); 72 | myQueue.printQueue(); 73 | for (int i = 1; i <= 6; ++i) { 74 | println("Enqueue " + i); 75 | myQueue.enqueue(i); 76 | } 77 | myQueue.printQueue(); 78 | for (int i = 1; i <= 3; ++i) { 79 | int item = myQueue.dequeue(); 80 | println("Dequeue " + item); 81 | } 82 | myQueue.printQueue(); 83 | for (int i = 1; i <= 3; ++i) { 84 | println("Enqueue " + i); 85 | myQueue.enqueue(i); 86 | } 87 | myQueue.printQueue(); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/chap03/Q6.java: -------------------------------------------------------------------------------- 1 | package chap03; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Arrays; 6 | import java.util.Stack; 7 | 8 | /** 9 | * Write a program to sort a stack in ascending order (with 10 | * biggest items on top). You may use at most one additional 11 | * stack to hold items, but you may not copy the elements into 12 | * any other data structure (such as an array). The stack supports 13 | * the following operations: push, pop, peek, and isEmpty. 14 | */ 15 | public class Q6 { 16 | // O(n^2) time and O(n) space 17 | public static Stack sortStack(Stack stack) { 18 | Stack result = new Stack(); 19 | while (!stack.isEmpty() ) { 20 | int item = stack.pop(); 21 | while (!result.isEmpty() && item < result.peek()) { 22 | stack.push(result.pop()); 23 | } 24 | result.push(item); 25 | } 26 | return result; 27 | } 28 | 29 | //TEST---------------------------------- 30 | public static void main(String[] args) { 31 | Integer[] a = {2,6,5,4,1,3,8,7}; 32 | Stack stack = new Stack(); 33 | stack.addAll(Arrays.asList(a)); 34 | print(sortStack(stack)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/chap03/Q7.java: -------------------------------------------------------------------------------- 1 | package chap03; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.LinkedList; 6 | 7 | /** 8 | * An animal shelter holds only dogs and cats, and operates on a strictly 9 | * "first in, first out" basis. People must adopt either the "oldest" 10 | * (based on arrival time) of all animals at the shelter, or they can 11 | * select whether they would prefer a dog or a cat (and will receive 12 | * the oldest animal of that type). They cannot select which specific 13 | * animal they would like. Create the data structures to maintain this 14 | * system and implement operations such as enqueue, dequeueAny, dequeueDog 15 | * and dequeueCat.You may use the built-in LinkedList data structure. 16 | */ 17 | public class Q7 { 18 | static class Animal { 19 | String name; 20 | long timestamp; 21 | public Animal(String n) { 22 | name = n; 23 | timestamp = System.nanoTime(); 24 | } 25 | } 26 | static class Dog extends Animal { 27 | public Dog(String n) { super(n); } 28 | public String toString() { 29 | return "Dog:" + name + ":" + timestamp; 30 | } 31 | } 32 | static class Cat extends Animal { 33 | public Cat(String n) { super(n); } 34 | public String toString() { 35 | return "Cat:" + name + ":" + timestamp; 36 | } 37 | } 38 | 39 | private LinkedList dogs = new LinkedList(); 40 | private LinkedList cats = new LinkedList(); 41 | 42 | public void enqueue(Animal a) { 43 | if (a instanceof Dog) { 44 | dogs.add((Dog) a); 45 | } else if (a instanceof Cat) { 46 | cats.add((Cat) a); 47 | } else { 48 | throw new IllegalArgumentException("Unknown type of animal!"); 49 | } 50 | } 51 | 52 | public Dog dequeueDog() { 53 | if (noDog()) throw new IllegalStateException("No dogs!"); 54 | return dogs.removeFirst(); 55 | } 56 | 57 | public Cat dequeueCat() { 58 | if (noCat()) throw new IllegalStateException("No cats!"); 59 | return cats.removeFirst(); 60 | } 61 | 62 | public Animal dequeueAny() { 63 | if (noAnimal()) { 64 | throw new IllegalStateException("No animals!"); 65 | } else if (noDog()) { 66 | return dequeueCat(); 67 | } else if (noCat()) { 68 | return dequeueDog(); 69 | } else if (peekDog().timestamp < peekCat().timestamp) { 70 | return dequeueDog(); 71 | } else { 72 | return dequeueCat(); 73 | } 74 | } 75 | 76 | public Dog peekDog() { 77 | if (noDog()) throw new IllegalStateException("No dogs!"); 78 | return dogs.getFirst(); 79 | } 80 | 81 | public Cat peekCat() { 82 | if (noDog()) throw new IllegalStateException("No cats!"); 83 | return cats.getFirst(); 84 | } 85 | 86 | public Animal peekAny() { 87 | if (noAnimal()) { 88 | throw new IllegalStateException("No animals!"); 89 | } else if (noDog()) { 90 | return peekCat(); 91 | } else if (noCat()) { 92 | return peekDog(); 93 | } else if (peekDog().timestamp < peekCat().timestamp) { 94 | return peekDog(); 95 | } else { 96 | return peekCat(); 97 | } 98 | } 99 | 100 | public boolean noDog() { 101 | return dogs.isEmpty(); 102 | } 103 | 104 | public boolean noCat() { 105 | return cats.isEmpty(); 106 | } 107 | 108 | public boolean noAnimal() { 109 | return noDog() && noCat(); 110 | } 111 | 112 | //TEST---------------------------------- 113 | public static void main(String[] args) { 114 | Q7 shelter = new Q7(); 115 | shelter.enqueue(new Cat("lily")); 116 | shelter.enqueue(new Dog("tom")); 117 | shelter.enqueue(new Dog("peter")); 118 | shelter.enqueue(new Cat("john")); 119 | shelter.enqueue(new Cat("anne")); 120 | println(shelter.dequeueAny()); 121 | println(shelter.dequeueCat()); 122 | println(shelter.dequeueAny()); 123 | shelter.enqueue(new Dog("tom")); 124 | println(shelter.dequeueDog()); 125 | println(shelter.dequeueAny()); 126 | println(shelter.dequeueAny()); 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/chap04/Q1.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.TreeNode; 6 | 7 | /** 8 | * Implement a function to check if a binary tree is balanced. 9 | * For the purposes of this question, a balanced tree is defined 10 | * to be a tree such that the heights of the two subtrees of any 11 | * node never differ by more than one. 12 | */ 13 | public class Q1 { 14 | // top-down: O(n^2) time 15 | public static boolean isBalanced(TreeNode n) { 16 | if (n == null) return true; 17 | return Math.abs(getHeight(n.left) - getHeight(n.right)) <= 1 && 18 | isBalanced(n.left) && 19 | isBalanced(n.right); 20 | } 21 | 22 | // bottom-up: O(n) time 23 | public static boolean isBalanced2(TreeNode n) { 24 | return getHeightBalanced(n) != -1; 25 | } 26 | 27 | private static int getHeight(TreeNode n) { 28 | if (n == null) return 0; 29 | return 1 + Math.max(getHeight(n.left), getHeight(n.right)); 30 | } 31 | 32 | private static int getHeightBalanced(TreeNode n) { 33 | if (n == null) return 0; 34 | int leftHeight = getHeightBalanced(n.left); 35 | int rightHeight = getHeightBalanced(n.right); 36 | if (leftHeight == -1 || rightHeight == -1) return -1; 37 | if (Math.abs(leftHeight - rightHeight) > 1) return -1; 38 | return 1 + Math.max(leftHeight, rightHeight); 39 | } 40 | 41 | //TEST---------------------------------- 42 | public static void main(String[] args) { 43 | /* 44 | * 4 45 | * / \ 46 | * 1 5 47 | * / \ 48 | * 2 3 49 | */ 50 | TreeNode n1 = new TreeNode(1), n2 = new TreeNode(3), r = new TreeNode(4); 51 | n1.left = new TreeNode(2); n1.right = n2; 52 | r.left = n1; r.right = new TreeNode(5); 53 | TreeNode.printTree(r); 54 | print(isBalanced(r) + " "); 55 | println(isBalanced2(r)); 56 | 57 | /* 58 | * 4 59 | * / \ 60 | * 1 5 61 | * / \ 62 | * 2 3 63 | * \ 64 | * 6 65 | */ 66 | n2.right = new TreeNode(6); 67 | TreeNode.printTree(r); 68 | print(isBalanced(r) + " "); 69 | print(isBalanced2(r)); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/chap04/Q2.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.LinkedList; 6 | import java.util.Queue; 7 | import java.util.Stack; 8 | 9 | import helpers.GraphNode; 10 | 11 | /** 12 | * Given a directed graph, design an algorithm to find out 13 | * whether there is a route between two nodes. 14 | */ 15 | public class Q2 { 16 | public static boolean DFSRecursive(GraphNode n1, GraphNode n2) { 17 | if (n1 == null || n2 == null) return false; 18 | n1.isVisited = true; 19 | if (n1 == n2) return true; 20 | for (GraphNode child : n1.adjacent) { 21 | if (!child.isVisited) { 22 | if(DFSRecursive(child, n2)) return true; 23 | } 24 | } 25 | return false; 26 | } 27 | 28 | public static boolean DFSIterative(GraphNode n1, GraphNode n2) { 29 | if (n1 == null || n2 == null) return false; 30 | Stack stack = new Stack(); 31 | stack.push(n1); 32 | while(!stack.isEmpty()) { 33 | GraphNode n = stack.pop(); 34 | if (!n.isVisited) { 35 | n.isVisited = true; 36 | if (n == n2) return true; 37 | stack.addAll(n.adjacent); 38 | } 39 | } 40 | return false; 41 | } 42 | 43 | public static boolean BFS(GraphNode n1, GraphNode n2) { 44 | if (n1 == null || n2 == null) return false; 45 | Queue queue = new LinkedList(); 46 | queue.add(n1); 47 | while (!queue.isEmpty()) { 48 | GraphNode n = queue.remove(); 49 | if (!n.isVisited) { 50 | n.isVisited = true; 51 | if (n == n2) return true; 52 | queue.addAll(n.adjacent); 53 | } 54 | } 55 | return false; 56 | } 57 | 58 | //TEST---------------------------------- 59 | public static void main(String[] args) { 60 | /* 61 | * 1->2 62 | * | /| 63 | * v/ | 64 | * v v 65 | * 3->4 66 | */ 67 | GraphNode n1 = new GraphNode(1); 68 | GraphNode n2 = new GraphNode(2); 69 | GraphNode n3 = new GraphNode(3); 70 | GraphNode n4 = new GraphNode(4); 71 | n1.adjacent.add(n2);n1.adjacent.add(n3); 72 | n2.adjacent.add(n3);n2.adjacent.add(n4); 73 | n3.adjacent.add(n4); 74 | 75 | println(DFSRecursive(n2, n4)); resetVisited(n1, n2, n3, n4); 76 | println(DFSIterative(n2, n4)); resetVisited(n1, n2, n3, n4); 77 | println(BFS(n2, n4)); resetVisited(n1, n2, n3, n4); 78 | println(DFSRecursive(n4, n1)); resetVisited(n1, n2, n3, n4); 79 | println(DFSIterative(n4, n1)); resetVisited(n1, n2, n3, n4); 80 | println(BFS(n4, n1)); resetVisited(n1, n2, n3, n4); 81 | } 82 | 83 | private static void resetVisited(GraphNode... nodes) { 84 | for (GraphNode n : nodes) n.isVisited = false; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/chap04/Q3.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.TreeNode; 6 | 7 | /** 8 | * Given a sorted (increasing order) array with unique integer 9 | * elements, write an algorithm to create a binary search tree 10 | * with minimal height. 11 | */ 12 | public class Q3 { 13 | public static TreeNode createBST(int[] a) { 14 | if (a == null) return null; 15 | return createBST(a, 0, a.length - 1); 16 | } 17 | 18 | private static TreeNode createBST(int[] a, int start, int end) { 19 | if (start > end) return null; 20 | int mid = start + (end - start) / 2; 21 | TreeNode n = new TreeNode(a[mid]); 22 | n.left = createBST(a, start, mid - 1); 23 | n.right = createBST(a, mid + 1, end); 24 | return n; 25 | } 26 | 27 | //TEST---------------------------------- 28 | public static void main(String[] args) { 29 | TreeNode.printTree(createBST(new int[] {})); 30 | println(); 31 | TreeNode.printTree(createBST(new int[] {0})); 32 | println(); 33 | TreeNode.printTree(createBST(new int[] {0,1})); 34 | println(); 35 | TreeNode.printTree(createBST(new int[] {0,1,2,3,4})); 36 | println(); 37 | TreeNode.printTree(createBST(new int[] {-1,0,1,3,4,7,9})); 38 | println(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/chap04/Q4.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.print; 4 | import static helpers.Printer.println; 5 | import helpers.TreeNode; 6 | 7 | import java.util.ArrayList; 8 | import java.util.LinkedList; 9 | import java.util.Queue; 10 | 11 | /** 12 | * Given a binary tree, design an algorithm which creates a linked 13 | * list of all the nodes at each depth (e.g., if you have a tree 14 | * with depth D, you'll have D linked lists). 15 | */ 16 | public class Q4 { 17 | public static ArrayList> createLevelLinkedList(TreeNode root) { 18 | ArrayList> result = new ArrayList>(); 19 | LinkedList current = new LinkedList(); 20 | if (root != null) current.add(root); 21 | while (!current.isEmpty()) { 22 | result.add(current); 23 | LinkedList parents = current; 24 | current = new LinkedList(); 25 | for (TreeNode parent : parents) { 26 | if (parent.left != null) current.add(parent.left); 27 | if (parent.right != null) current.add(parent.right); 28 | } 29 | } 30 | return result; 31 | } 32 | 33 | public static ArrayList> createLevelLinkedList2(TreeNode root) { 34 | ArrayList> result = new ArrayList>(); 35 | Queue q = new LinkedList(); 36 | if (root != null) q.add(root); 37 | while(!q.isEmpty()) { 38 | int size = q.size(); 39 | LinkedList level = new LinkedList(); 40 | for (int i = 0; i < size; ++i) { 41 | TreeNode n = q.remove(); 42 | level.add(n); 43 | if (n.left != null) q.add(n.left); 44 | if (n.right != null) q.add(n.right); 45 | } 46 | result.add(level); 47 | } 48 | return result; 49 | } 50 | 51 | //TEST---------------------------------- 52 | public static void main(String[] args) { 53 | /* 54 | * 4 55 | * / \ 56 | * 1 5 57 | * / \ \ 58 | * 2 3 7 59 | * \ 60 | * 6 61 | */ 62 | TreeNode n1 = new TreeNode(1), n2 = new TreeNode(3), 63 | n3 = new TreeNode(5), r = new TreeNode(4); 64 | n1.left = new TreeNode(2); n1.right = n2; n2.right = new TreeNode(6); 65 | r.left = n1; r.right = n3; n3.right = new TreeNode(7); 66 | TreeNode.printTree(r); 67 | println(); 68 | 69 | println("createLevelLinkedList:"); 70 | ArrayList> levels = createLevelLinkedList(r); 71 | for (LinkedList level : levels) { 72 | for (TreeNode node : level) { 73 | print(node + " "); 74 | } 75 | println(); 76 | } 77 | println("\ncreateLevelLinkedList2:"); 78 | levels = createLevelLinkedList2(r); 79 | for (LinkedList level : levels) { 80 | for (TreeNode node : level) { 81 | print(node + " "); 82 | } 83 | println(); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/chap04/Q5.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.TreeNode; 6 | 7 | /** 8 | * Implement a function to check if a binary tree is a binary search 9 | * tree. More precisely, the condition is that ALL left nodes must be 10 | * less than or equal to the current node, which must be less than ALL 11 | * the right nodes (for all nodes). 12 | */ 13 | public class Q5 { 14 | public static boolean isBSTNaive(TreeNode n) { 15 | if (n == null) return true; 16 | return smallerThan(n.left, n.value) && 17 | largerThan(n.right, n.value) && 18 | isBSTNaive(n.left) && 19 | isBSTNaive(n.right); 20 | } 21 | 22 | private static boolean largerThan(TreeNode n, int val) { 23 | if (n == null) return true; 24 | return n.value > val && largerThan(n.left, val) && largerThan(n.right, val); 25 | } 26 | 27 | private static boolean smallerThan(TreeNode n, int val) { 28 | if (n == null) return true; 29 | return n.value <= val && smallerThan(n.left, val) && smallerThan(n.right, val); 30 | } 31 | 32 | public static boolean isBST(TreeNode n) { 33 | return isBST(n, Integer.MIN_VALUE, Integer.MAX_VALUE); 34 | } 35 | 36 | private static boolean isBST(TreeNode n, int min, int max) { 37 | if (n == null) return true; 38 | if (n.value <= min || n.value > max) return false; 39 | return isBST(n.left, min, n.value) && isBST(n.right, n.value, max); 40 | } 41 | 42 | // wrong implementation 43 | public static boolean isBSTWrong(TreeNode n) { 44 | if (n == null) return true; 45 | if (n.left != null && n.left.value > n.value) return false; 46 | if (n.right != null && n.right.value <= n.value) return false; 47 | return isBSTWrong(n.left) && isBSTWrong(n.right); 48 | } 49 | 50 | //TEST---------------------------------- 51 | public static void main(String[] args) { 52 | /* 53 | * 4 54 | * / \ 55 | * 2 5 56 | * / \ 57 | * 1 3 58 | */ 59 | TreeNode n1 = new TreeNode(2), n2 = new TreeNode(3), r = new TreeNode(4); 60 | n1.left = new TreeNode(1); n1.right = n2; 61 | r.left = n1; r.right = new TreeNode(5); 62 | TreeNode.printTree(r); 63 | println("isBSTNaive: " + isBSTNaive(r)); 64 | println("isBST: " + isBST(r)); 65 | println("isBSTWrong: " + isBSTWrong(r)); 66 | println(); 67 | /* 68 | * 2 69 | * / \ 70 | * 1 4 71 | * \ 72 | * 3 73 | */ 74 | n1 = new TreeNode(1); n1.right = new TreeNode(3); 75 | r = new TreeNode(2); r.left = n1; r.right = new TreeNode(4); 76 | TreeNode.printTree(r); 77 | println("isBSTNaive: " + isBSTNaive(r)); 78 | println("isBST: " + isBST(r)); 79 | println("isBSTWrong: " + isBSTWrong(r)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/chap04/Q6.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.TreeNode; 6 | 7 | /** 8 | * Write an algorithm to find the 'next' node (i.e., in-order successor) 9 | * of a given node in a binary search tree. You may assume that each node 10 | * has a link to its parent. 11 | */ 12 | public class Q6 { 13 | public static TreeNode inorderSuccessor(TreeNode n) { 14 | if (n == null) return null; 15 | 16 | // case 1: n has right subtree -> 17 | // return leftmost node of right subtree 18 | if (n.right != null) return leftmostChild(n.right); 19 | 20 | // case 2: n has no right subtree 21 | // case 2.1: n is left child of its parent -> 22 | // just return its parent 23 | // case 2.2: n is right child of its parent -> 24 | // n goes up until n is left child of its parent, 25 | // then return this parent 26 | // case 3: n is the last node in traversal -> 27 | // return root's parent, ie., null 28 | while (n.parent != null && n.parent.right == n) { 29 | n = n.parent; 30 | } 31 | return n.parent; 32 | } 33 | 34 | private static TreeNode leftmostChild(TreeNode n) { 35 | if (n.left == null) return n; 36 | return leftmostChild(n.left); 37 | } 38 | 39 | public static TreeNode preorderSuccessor(TreeNode n) { 40 | if (n == null) return null; 41 | 42 | // case 1: n has a child -> 43 | // just return that child (left if exists, otherwise right) 44 | if (n.left != null) return n.left; 45 | else if (n.right != null) return n.right; 46 | // case 2: n has no child -> 47 | // n climbs up until reaching a parent that has a right child 48 | // (which is not n), then return this right child 49 | while (n.parent != null && (n.parent.right == null || n.parent.right == n)) { 50 | n = n.parent; 51 | } 52 | // case 3: n is the last node in traversal -> 53 | // return root's parent, ie., null 54 | if (n.parent == null) return null; 55 | return n.parent.right; 56 | } 57 | 58 | public static TreeNode postorderSuccessor(TreeNode n) { 59 | // case 1: n is the last node in traversal -> 60 | // return root's parent, ie., null 61 | if (n == null || n.parent == null) return null; 62 | // case 2: n is left child of its parent -> 63 | // just return parent 64 | // case 3: n is right child of its parent 65 | // case 3.1: parent has no right child -> 66 | // just return parent 67 | if (n.parent.right == n || n.parent.right == null) return n.parent; 68 | // case 3.2: parent has right child -> 69 | // return leftmost bottom node of parent's right subtree 70 | return leftmostBottomChild(n.parent.right); 71 | } 72 | 73 | private static TreeNode leftmostBottomChild(TreeNode n) { 74 | if (n.left == null && n.right == null) return n; 75 | if (n.left != null) { 76 | return leftmostBottomChild(n.left); 77 | } else { 78 | return leftmostBottomChild(n.right); 79 | } 80 | } 81 | 82 | //TEST---------------------------------- 83 | public static void main(String[] args) { 84 | /* 85 | * 4 86 | * / \ 87 | * 2 5 88 | * / \ 89 | * 1 3 90 | */ 91 | TreeNode n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), 92 | n4 = new TreeNode(4), n5 = new TreeNode(5); 93 | n2.left = n1; n2.right = n3; n1.parent = n2; n3.parent = n2; 94 | n4.left = n2; n4.right = n5; n2.parent = n4; n5.parent = n4; 95 | TreeNode.printTree(n4); 96 | 97 | TreeNode n = n4; 98 | print("pre-order: "); 99 | while (n != null) { 100 | print(n + " "); 101 | n = preorderSuccessor(n); 102 | } 103 | print("\nin-order: "); 104 | n = n1; 105 | while (n != null) { 106 | print(n + " "); 107 | n = inorderSuccessor(n); 108 | } 109 | print("\npost-order: "); 110 | n = n1; 111 | while (n != null) { 112 | print(n + " "); 113 | n = postorderSuccessor(n); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/chap04/Q7.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.TreeNode; 6 | 7 | /** 8 | * Design an algorithm and write code to find the first common 9 | * ancestor of two nodes in a binary tree. Avoid storing additional 10 | * nodes in a data structure. NOTE: This is not necessarily a binary 11 | * search tree. 12 | */ 13 | public class Q7 { 14 | public static TreeNode findFirstCommonAncestor(TreeNode root, TreeNode n1, TreeNode n2) { 15 | if (root == null) return null; 16 | if (root == n1 && contains(root, n2) || 17 | root == n2 && contains(root, n1)) return root; 18 | boolean n1OnLeft = contains(root.left, n1); 19 | boolean n2OnLeft = contains(root.left, n2); 20 | if (n1OnLeft && n2OnLeft) { 21 | return findFirstCommonAncestor(root.left, n1, n2); 22 | } else if (!n1OnLeft && !n2OnLeft) { 23 | return findFirstCommonAncestor(root.right, n1, n2); 24 | } else { 25 | return root; 26 | } 27 | } 28 | 29 | private static boolean contains(TreeNode root, TreeNode n) { 30 | if (root == null) return false; 31 | if (root == n) return true; 32 | return contains(root.left, n) || contains(root.right, n); 33 | } 34 | 35 | //TEST---------------------------------- 36 | public static void main(String[] args) { 37 | /* 38 | * 4 39 | * / \ 40 | * 2 5 41 | * / \ \ 42 | * 1 3 7 43 | * / 44 | * 6 45 | */ 46 | TreeNode n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), 47 | n4 = new TreeNode(4), n5 = new TreeNode(5), n6 = new TreeNode(6), 48 | n7 = new TreeNode(7); 49 | n2.left = n1; n2.right = n3; n4.left = n2; n4.right = n5; n3.left = n6; 50 | n5.right = n7; 51 | TreeNode.printTree(n4); 52 | println(); 53 | printfln("FirstCommonAncestor of %s, %s: %s", n1, n6, findFirstCommonAncestor(n4, n1, n6)); 54 | printfln("FirstCommonAncestor of %s, %s: %s", n1, n7, findFirstCommonAncestor(n4, n1, n7)); 55 | printfln("FirstCommonAncestor of %s, %s: %s", n4, n5, findFirstCommonAncestor(n4, n4, n5)); 56 | printfln("FirstCommonAncestor of %s, %s: %s", n5, n5, findFirstCommonAncestor(n4, n5, n5)); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/chap04/Q8.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import helpers.TreeNode; 6 | 7 | /** 8 | * You have two very large binary trees: Tl, with millions of 9 | * nodes, and T2, with hundreds of nodes. Create an algorithm 10 | * to decide if T2 is a subtree of Tl. A tree T2 is a subtree 11 | * of Tl if there exists a node n in Tl such that the subtree 12 | * of n is identical to T2. That is, if you cut off the tree 13 | * at node n, the two trees would be identical. 14 | */ 15 | public class Q8 { 16 | public static boolean isSubtree(TreeNode t1, TreeNode t2) { 17 | if (t2 == null) return true; 18 | if (t1 == null) return false; 19 | if (isIdentical(t1, t2)) return true; 20 | return isSubtree(t1.left, t2) || 21 | isSubtree(t1.right, t2); 22 | } 23 | 24 | private static boolean isIdentical(TreeNode n1, TreeNode n2) { 25 | if (n1 == null && n2 == null) return true; 26 | if (n1 == null || n2 == null) return false; 27 | if (n1.value != n2.value) return false; 28 | return isIdentical(n1.left, n2.left) && 29 | isIdentical(n1.right, n2.right); 30 | } 31 | 32 | /* Alternative: 33 | * Compare whether T2's leaf-delimited traversal string (pre-order, 34 | * in-order, etc) is a substring of T1's. Fast but waste memory, not 35 | * good for large trees. 36 | */ 37 | public static boolean isSubtree2(TreeNode t1, TreeNode t2) { 38 | return getTraversalStr(t1).contains(getTraversalStr(t2)); 39 | } 40 | 41 | private static String getTraversalStr(TreeNode n) { 42 | StringBuilder sb = new StringBuilder(); 43 | preorderTraverse(n, sb); 44 | return sb.toString(); 45 | } 46 | 47 | private static void preorderTraverse(TreeNode n, StringBuilder sb) { 48 | if (n == null) { 49 | sb.append("\0"); 50 | } else { 51 | sb.append(n.value); 52 | preorderTraverse(n.left, sb); 53 | preorderTraverse(n.right, sb); 54 | } 55 | } 56 | 57 | //TEST---------------------------------- 58 | public static void main(String[] args) { 59 | /* 60 | * 4 61 | * / \ 62 | * 2 5 63 | * / \ \ 64 | * 1 3 7 65 | * / 66 | * 6 67 | */ 68 | TreeNode n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), 69 | n4 = new TreeNode(4), n5 = new TreeNode(5), n6 = new TreeNode(6), 70 | n7 = new TreeNode(7); 71 | n2.left = n1; n2.right = n3; n4.left = n2; n4.right = n5; n3.left = n6; 72 | n5.right = n7; 73 | TreeNode.printTree(n4); 74 | println(); 75 | println(isSubtree(n4, n2)); 76 | println(isSubtree2(n4, n2)); 77 | println(); 78 | println(isSubtree(n2, n5)); 79 | println(isSubtree2(n2, n5)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/chap04/Q9.java: -------------------------------------------------------------------------------- 1 | package chap04; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.LinkedList; 6 | 7 | import helpers.TreeNode; 8 | 9 | /** 10 | * You are given a binary tree in which each node contains a 11 | * value. Design an algorithm to print all paths which sum to 12 | * a given value. The path does not need to start or end at 13 | * the root or a leaf. 14 | */ 15 | public class Q9 { 16 | public static LinkedList> findSumPaths(TreeNode root, int target) { 17 | LinkedList> result = new LinkedList>(); 18 | findSumPaths(root, target, new LinkedList(), result); 19 | return result; 20 | } 21 | 22 | @SuppressWarnings("unchecked") 23 | private static void findSumPaths(TreeNode n, int target, LinkedList path, LinkedList> result) { 24 | if (n == null) return; 25 | path.add(n); 26 | int sum = 0; 27 | LinkedList nodes = new LinkedList(); 28 | for (int i = path.size() - 1; i >= 0; --i) { 29 | TreeNode node = path.get(i); 30 | nodes.add(node); 31 | sum += node.value; 32 | if (sum == target) { 33 | result.add((LinkedList) nodes.clone()); 34 | } 35 | } 36 | findSumPaths(n.left, target, path, result); 37 | findSumPaths(n.right, target, path, result); 38 | 39 | // "Pop" recursion stack top. 40 | // Alternatively, clone path when passing it in recursive 41 | // calls, or use native array to hold path. 42 | path.removeLast(); 43 | } 44 | 45 | //TEST---------------------------------- 46 | public static void main(String[]args) { 47 | /* 48 | * 4 49 | * / \ 50 | * 5 2 51 | * / \ \ 52 | * 1 3 7 53 | * \ / / 54 | * 8 6 9 55 | */ 56 | TreeNode n1 = new TreeNode(1), n2 = new TreeNode(2), n3 = new TreeNode(3), 57 | n4 = new TreeNode(4), n5 = new TreeNode(5), n6 = new TreeNode(6), 58 | n7 = new TreeNode(7), n8 = new TreeNode(8), n9 = new TreeNode(9); 59 | n4.left = n5; n4.right = n2; n5.left = n1; n5.right = n3; n1.right = n8; 60 | n3.left = n6; n2.right = n7; n7.left = n9; 61 | TreeNode.printTree(n4); 62 | println(); 63 | LinkedList> result = findSumPaths(n4, 9); 64 | printResult(result); 65 | result = findSumPaths(n4, 6); 66 | printResult(result); 67 | } 68 | 69 | private static void printResult(LinkedList> result) { 70 | for (LinkedList path : result) { 71 | for (TreeNode n : path) { 72 | print(n + " "); 73 | } 74 | println(); 75 | } 76 | println(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/chap05/Q1.java: -------------------------------------------------------------------------------- 1 | package chap05; 2 | 3 | import static helpers.Printer.*; 4 | import static helpers.Bit.*; 5 | 6 | /** 7 | * You are given two 32-bit numbers, N and M, and two bit positions, 8 | * i and j. Write a method to insert M into N such that M starts at 9 | * bit j and ends at bit i. You can assume that the bits j through i 10 | * have enough space to fit all of M. That is, if M = 10011, you can 11 | * assume that there are at least 5 bits between j and i. You would 12 | * not, for example, have j = 3 and i = 2, because M could not fully 13 | * fit between bit 3 and bit 2. 14 | * 15 | * EXAMPLE 16 | * Input: N = 10000000000, M = 10011, i = 2, j = 6 17 | * Output: N = 10001001100 18 | * 19 | * Key: 20 | * First create mask 11110000011 on N, then place M into N. 21 | */ 22 | public class Q1 { 23 | public static int updateBits(int n, int m, int i, int j) { 24 | int allOnes = ~0; 25 | int left = allOnes << (j + 1); 26 | int right = (1 << i) - 1; 27 | int mask = left | right; 28 | // clear bit & set bit 29 | return (n & mask) | (m << i); 30 | } 31 | 32 | public static int updateBits2(int n, int m, int i, int j) { 33 | int mask = ~((1 << (j+1)) - (1 << i)); 34 | return (n & mask) | (m << i); 35 | } 36 | 37 | //TEST---------------------------------- 38 | public static void main(String[] args) { 39 | int n = toInt("1010011011"), m = toInt("11010"); 40 | int i = 2, j = 6; 41 | println(toBitString(updateBits(n, m, i, j))); 42 | println(toBitString(updateBits2(n, m, i, j))); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/chap05/Q2.java: -------------------------------------------------------------------------------- 1 | package chap05; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given a real number between 0 and 1 (e.g., 0.72) that is passed 7 | * in as a double, print the binary representation. If the number 8 | * cannot be represented accurately in binary with at most 32 9 | * characters, print "ERROR". 10 | */ 11 | public class Q2 { 12 | /* Key: 13 | * To print the decimal part, multiply it by 2, 14 | * if 2*n is greater than or equal to 1: append bit 1 15 | * else: append bit 0 16 | */ 17 | public static String printBinary(double n) { 18 | StringBuilder sb = new StringBuilder(); 19 | sb.append("0."); 20 | while (n > 0) { 21 | if (n * 2 >= 1) { 22 | sb.append(1); 23 | n = n * 2 - 1; 24 | } else { 25 | sb.append(0); 26 | n *= 2; 27 | } 28 | if (sb.length() > 32) { 29 | return "ERROR(" + sb.toString() + ")"; 30 | } 31 | } 32 | return sb.toString(); 33 | } 34 | 35 | //TEST---------------------------------- 36 | public static void main(String[] args) { 37 | println(printBinary(0.0)); 38 | println(printBinary(0.25)); 39 | println(printBinary(0.025)); 40 | println(printBinary(0.75)); 41 | println(printBinary(0.750001)); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/chap05/Q3.java: -------------------------------------------------------------------------------- 1 | package chap05; 2 | 3 | import static helpers.Printer.*; 4 | import static helpers.Bit.*; 5 | 6 | /** 7 | * Given a positive integer, print the next smallest and the next 8 | * largest number that have the same number of 1 bits in their 9 | * binary representation. 10 | */ 11 | public class Q3 { 12 | public static int getNext(int n) { 13 | assert n > 0; 14 | int numOnes = countNumOnes(n); 15 | for (int i = n + 1; i <= Integer.MAX_VALUE; ++i) { 16 | if (countNumOnes(i) == numOnes) 17 | return i; 18 | } 19 | return -1; 20 | } 21 | 22 | public static int getPrev(int n) { 23 | assert n > 0; 24 | int numOnes = countNumOnes(n); 25 | for (int i = n - 1; i > 0; --i) { 26 | if (countNumOnes(i) == numOnes) 27 | return i; 28 | } 29 | return -1; 30 | } 31 | 32 | private static int countNumOnes(int n) { 33 | int cnt = 0; 34 | for (int i = n; i > 0; i &= (i - 1)) { 35 | ++cnt; 36 | } 37 | return cnt; 38 | } 39 | 40 | //TEST---------------------------------- 41 | public static void main(String[] args) { 42 | test(5); 43 | test(50); 44 | } 45 | 46 | private static void test(int n) { 47 | println(n + " (" + toBitString(n) + ")"); 48 | int next = getNext(n), prev = getPrev(n); 49 | println("next: " + next + " ("+ toBitString(next) + ")"); 50 | println("prev: " + prev + " ("+ toBitString(prev) + ")"); 51 | println(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/chap05/Q4.txt: -------------------------------------------------------------------------------- 1 | Explain what the following code does: ((n & (n-1)) == 0). 2 | 3 | SOLUTION 4 | 5 | Checks whether n is a power of 2. -------------------------------------------------------------------------------- /src/chap05/Q5.java: -------------------------------------------------------------------------------- 1 | package chap05; 2 | 3 | import static helpers.Printer.*; 4 | import static helpers.Bit.*; 5 | 6 | /** 7 | * Write a function to determine the number of bits required to 8 | * convert integer A to integer B. 9 | * 10 | * EXAMPLE 11 | * Input: 31, 14 (11111, 01110) 12 | * Output: 2 13 | */ 14 | public class Q5 { 15 | public static int bitsFlipRequired(int a, int b) { 16 | int cnt = 0; 17 | int diff = a ^ b; 18 | for (int i = diff; i > 0; i &= i - 1) ++cnt; 19 | return cnt; 20 | } 21 | 22 | //TEST---------------------------------- 23 | public static void main(String[] args) { 24 | int a = 101, b = 140; 25 | println(toBitString(a) + " " + toBitString(b)); 26 | println("bitsFlipRequired: " + bitsFlipRequired(a, b)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/chap05/Q6.java: -------------------------------------------------------------------------------- 1 | package chap05; 2 | 3 | import static helpers.Printer.*; 4 | import static helpers.Bit.*; 5 | 6 | /** 7 | * Write a program to swap odd and even bits in an integer with 8 | * as few instructions as possible (e.g., bit 0 and bit 1 are 9 | * swapped, bit 2 and bit 3 are swapped, and so on). 10 | */ 11 | public class Q6 { 12 | public static int swapOddEvenBits(int n) { 13 | // Key: 14 | // 0xAAAAAAAA -> mask: 10101010... 15 | // 0x55555555 -> mask: 01010101... 16 | // for 32-bit integers 17 | return ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); 18 | } 19 | 20 | //TEST---------------------------------- 21 | public static void main(String[] args) { 22 | String bitString = "01001011"; 23 | int bits = toInt(bitString); 24 | println(bitString); 25 | println("swapOddEvenBits: " + toBitString(swapOddEvenBits(bits))); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/chap05/Q7.java: -------------------------------------------------------------------------------- 1 | package chap05; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | 9 | /** 10 | * An array A contains all the integers from 0 to n, except for 11 | * one number which is missing. In this problem, we cannot access 12 | * an entire integer in A with a single operation. The elements 13 | * of A are represented in binary, and the only operation we can 14 | * use to access them is "fetch the j-th bit of A[i]," which takes 15 | * constant time. Write code to find the missing integer. Can you 16 | * do it in 0(n) time? 17 | */ 18 | public class Q7 { 19 | /* SOLUTION 20 | * 1. Start with the first least significant bit (LSB(0)). 21 | * 2. Count occurrences of 1's vs 0's. 22 | * 3. If count(1) < count(0), then the missing number has a 1 as its LSB, 23 | * else it has a 0. 24 | * 4. Only retain all numbers with LSB matching result found in step 3. 25 | * 5. Repeat steps 1-4, iterating from least significant bit (LSB(0)) 26 | * -> 2nd least significant bit (LSB(1)) -> ... 27 | * -> most significant bit (LSB(N)) 28 | */ 29 | public static int findMissingInteger(ArrayList a) { 30 | int j = 0; 31 | int n = 0; 32 | while (a.size() > 0) { 33 | int bit = findMissingIntegerBit(a, j); 34 | n |= bit << j; 35 | a = filter(a, j, bit); 36 | ++j; 37 | } 38 | return n; 39 | } 40 | 41 | private static int findMissingIntegerBit(ArrayList a, int j) { 42 | int numOnes = 0; 43 | int numZeros = 0; 44 | for (int i = 0; i < a.size(); ++i) { 45 | int bit = fetch(a, i, j); 46 | if (bit == 1) ++numOnes; 47 | else ++numZeros; 48 | } 49 | if (numOnes < numZeros) return 1; 50 | else return 0; 51 | } 52 | 53 | private static ArrayList filter(ArrayList a, int j, int bit) { 54 | ArrayList result = new ArrayList(); 55 | for (int i = 0; i < a.size(); ++i) { 56 | if (fetch(a, i, j) == bit) 57 | result.add(a.get(i)); 58 | } 59 | return result; 60 | } 61 | 62 | private static int fetch(ArrayList a, int i, int j) { 63 | int n = a.get(i); 64 | return (n >> j) & 1; 65 | } 66 | 67 | //TEST---------------------------------- 68 | public static void main(String[] args) { 69 | Integer[] a = {0,1,2,3,5,6,7,8,9,10}; 70 | ArrayList list = new ArrayList(Arrays.asList(a)); 71 | Collections.shuffle(list); 72 | println(findMissingInteger(list)); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/chap05/Q8.java: -------------------------------------------------------------------------------- 1 | package chap05; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * A monochrome screen is stored as a single array of bytes, allowing eight consecutive pixels 7 | * to be stored in one byte.The screen has width w, where w is divisible by 8 (that is, no byte 8 | * will be split across rows). The height of the screen, of course, can be derived from the length 9 | * of the array and the width. Implement a function drawHorizontalLine(byte[] screen, int width, 10 | * int x1, int x2, int y) which draws a horizontal line from (x1, y) to (x2, y). 11 | */ 12 | public class Q8 { 13 | public static void drawLine(byte[] screen, int width, int x1, int x2, int y) { 14 | int startOffset = x1 % 8; 15 | int firstByte = startOffset == 0 ? x1/8 : x1/8 + 1; 16 | int endOffset = x2 % 8; 17 | int lastByte = endOffset == 7 ? x2/8 : x2/8 - 1; 18 | 19 | // draw line for full bytes 20 | for (int i = firstByte; i <= lastByte; ++i) { 21 | screen[i + width/8*y] = (byte) 0xFF; 22 | } 23 | 24 | // draw start and end of line 25 | byte startMask = (byte) (0xFF >> startOffset); 26 | byte endMask = (byte) ~(0xFF >> (endOffset + 1)); 27 | if (x1/8 == x2/8) { 28 | byte mask = (byte) (startMask & endMask); 29 | screen[x1/8 + width/8*y] |= mask; 30 | } 31 | else { 32 | if (startOffset != 0) { 33 | screen[firstByte - 1 + width/8*y] |= startMask; 34 | } 35 | if (endOffset != 7) { 36 | screen[lastByte + 1 + width/8*y] |= endMask; 37 | } 38 | } 39 | } 40 | 41 | //TEST---------------------------------- 42 | public static void main(String[] args) { 43 | byte[] screen = new byte[16]; 44 | int width = 32; 45 | printScreen(screen, width); 46 | drawLine(screen, width, 0, 6, 0); 47 | printScreen(screen, width); 48 | drawLine(screen, width, 31,31, 1); 49 | drawLine(screen, width, 2, 29, 2); 50 | drawLine(screen, width, 1, 5, 3); 51 | printScreen(screen, width); 52 | } 53 | 54 | private static void printScreen(byte[] screen, int width) { 55 | int num = 1, widthNum = width/8; 56 | for (byte b : screen) { 57 | for (int i = 7; i >= 0; --i) { 58 | print((b >> i) & 1); 59 | } 60 | if (num % widthNum == 0) println(); 61 | ++num; 62 | } 63 | println(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/chap07/Q1.txt: -------------------------------------------------------------------------------- 1 | You have a basketball hoop and someone says that you can play one of two 2 | games. 3 | Game 1: You get one shot to make the hoop. 4 | Game 2: You get three shots and you have to make two of three shots. 5 | If p is the probability of making a particular shot, for which values of p should 6 | you pick one game or the other? 7 | 8 | SOLUTION 9 | 10 | Game 1: 11 | P(game1) = p 12 | 13 | Game 2: 14 | P(game2)=P(make 1 and 2) + P(make 1 and 3) + P(make 2 and 3) + P(make 1, 2 and 3) 15 | =p*p*(1-p) + p*(1-p)*p + (1-p)*p*p + p*p*p 16 | =3p^2 - 2p^3 17 | 18 | play Game 1 if: 19 | P(game1) > P(game2) 20 | => p > 3p^2 - 2p^3 21 | => p(p-1)(2p-1) > 0 note that 0<=p<=1 22 | => p < 1/2 23 | 24 | If p = 0 or p = 1/2 or p = 1, then it doesn't matter which game to play. 25 | -------------------------------------------------------------------------------- /src/chap07/Q2.txt: -------------------------------------------------------------------------------- 1 | There are three ants on different vertices of a triangle. What is the probability of 2 | collision (between any two or all of them) if they start walking on the sides of the 3 | triangle? Assume that each ant randomly picks a direction, with either direction 4 | being equally likely to be chosen, and that they walk at the same speed. 5 | Similarly, find the probability of collision with n ants on an n-vertex polygon. 6 | 7 | SOLUTION 8 | 9 | P(clockwise)=(1/2)^3, 10 | P(counterclockwise)=(1/2)^3, 11 | so P(same_direction)=P(clockwise)+P(counterclockwise)=1/4, 12 | so P(collision)=1-P(same_direction)=3/4. 13 | 14 | P(clockwise)=(1/2)^n, 15 | P(counterclockwise)=(1/2)^n, 16 | so P(same_direction)=P(clockwise)+P(counterclockwise)=(1/2)^(n-1), 17 | so P(collision)=1-P(same_direction)=1-(1/2)^(n-1). 18 | -------------------------------------------------------------------------------- /src/chap07/Q3.java: -------------------------------------------------------------------------------- 1 | package chap07; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given two lines on a Cartesian plane, determine whether the two lines 7 | * would intersect. Two same lines are considered to be intersected. 8 | */ 9 | public class Q3 { 10 | public static class Line { 11 | static final double EPSILON = 0.0000001; 12 | double slope; 13 | double yintercept; 14 | public Line(double slope, double yintercept) { 15 | this.slope = slope; 16 | this.yintercept = yintercept; 17 | } 18 | } 19 | 20 | /* 21 | * Key: Don't assume that the slope and y-intercept are integers. 22 | * Understand limitations of floating point representations. Never check 23 | * for equality with ==. Instead, check if the difference is less than an 24 | * epsilon value. 25 | */ 26 | public static boolean intersect(Line l1, Line l2) { 27 | return Math.abs(l1.slope - l2.slope) > Line.EPSILON || 28 | Math.abs(l1.yintercept - l2.yintercept) < Line.EPSILON; 29 | } 30 | 31 | //TEST---------------------------------- 32 | public static void main(String[] args) { 33 | Line l1 = new Line(0.4, 0.79), l2 = new Line(0.5, 0.9), l3 = new Line(0.4, 1.3); 34 | println(intersect(l1, l2)); 35 | println(intersect(l3, l1)); 36 | println(intersect(l3, l3)); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/chap07/Q4.java: -------------------------------------------------------------------------------- 1 | package chap07; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write methods to implement the multiply, subtract, and divide 7 | * operations for integers. Use only the add operator. 8 | */ 9 | public class Q4 { 10 | // returns a + b 11 | public static int add(int a, int b) { 12 | if (a > 0 && b > Integer.MAX_VALUE - a) 13 | throw new IllegalArgumentException("Addition overflow!"); 14 | if (a < 0 && b < Integer.MIN_VALUE - a) 15 | throw new IllegalArgumentException("Addition underflow!"); 16 | return a + b; 17 | } 18 | 19 | // returns a - b 20 | public static int subtract(int a, int b) { 21 | return add(a, negate(b)); 22 | } 23 | 24 | // returns -a 25 | public static int negate(int a) { 26 | int base = a > 0 ? -1 : 1; 27 | int result = 0; 28 | while (a != 0) { 29 | a = add(a, base); 30 | result = add(result, base); 31 | } 32 | return result; 33 | } 34 | 35 | // returns a * b 36 | public static int multiply(int a, int b) { 37 | if (a == 0 || b == 0) return 0; 38 | int absA = abs(a), absB = abs(b); 39 | if (absA < absB) return multiply(b, a); 40 | boolean isNegative = a > 0 != b > 0; 41 | int result = 0; 42 | for (int i = 0; i < absB; ++i) { 43 | result = add(result, absA); 44 | } 45 | return isNegative ? negate(result) : result; 46 | } 47 | 48 | //returns a / b 49 | public static int divide(int a, int b) { 50 | if (a == 0) return 0; 51 | if (b == 0) throw new IllegalArgumentException("Divisor is zero!"); 52 | int absA = abs(a), absB = abs(b); 53 | boolean isNegative = a > 0 != b > 0; 54 | int sum = 0, result = 0; 55 | while (add(sum, absB) <= absA) { 56 | sum = add(sum, absB); 57 | result = add(result, 1); 58 | } 59 | return isNegative ? negate(result) : result; 60 | } 61 | 62 | // returns absolute value of a 63 | public static int abs(int a) { 64 | return a >= 0? a : negate(a); 65 | } 66 | 67 | //TEST---------------------------------- 68 | public static void main(String[] args) { 69 | test(9, 3); 70 | test(9, 4); 71 | test(0, -1); 72 | test(-100, 999); 73 | test(-23456,-56781); 74 | } 75 | 76 | private static void test(int a, int b) { 77 | printfln("%d + %d = %d", a, b, add(a, b)); 78 | printfln("%d - %d = %d", a, b, subtract(a, b)); 79 | printfln("%d * %d = %d", a, b, multiply(a, b)); 80 | printfln("%d / %d = %d", a, b, divide(a, b)); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/chap07/Q5.java: -------------------------------------------------------------------------------- 1 | package chap07; 2 | 3 | import java.util.ArrayList; 4 | 5 | /** 6 | * Given two squares on a two-dimensional plane, find a line that 7 | * would cut these two squares in half. Assume that the top and 8 | * the bottom sides of the square run parallel to the x-axis. 9 | */ 10 | public class Q5 { 11 | public Line findLine(Square s1, Square s2) { 12 | return new Line(mid(s1), mid(s2)); 13 | } 14 | 15 | private Point mid(Square s) { 16 | ArrayList points = s.points; 17 | int sumX = 0, sumY = 0, n = points.size(); 18 | for (Point p : points) { 19 | sumX += p.x; 20 | sumY += p.y; 21 | } 22 | return new Point(sumX / n, sumY / n); 23 | } 24 | 25 | public class Point { 26 | int x, y; 27 | public Point(int x, int y) { 28 | this.x = x; 29 | this.y = y; 30 | } 31 | } 32 | 33 | public class Line { 34 | Point p1, p2; 35 | public Line(Point p1, Point p2) { 36 | this.p1 = p1; 37 | this.p2 = p2; 38 | } 39 | } 40 | 41 | public class Square { 42 | ArrayList points; 43 | public Square(ArrayList points) { 44 | this.points = points; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/chap07/Q6.java: -------------------------------------------------------------------------------- 1 | package chap07; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | 8 | /** 9 | * Given a two-dimensional graph with points on it, find a line 10 | * which passes the most number of points. 11 | */ 12 | public class Q6 { 13 | private static final double EPSILON = 0.0000001; 14 | 15 | public static Line findBestLine(Point[] points) { 16 | Line bestLine = null; 17 | int bestCnt = 0; 18 | HashMap> lines = new HashMap>(); 19 | for (int i = 0; i < points.length; ++i) { 20 | for (int j = i + 1; j < points.length; ++j) { 21 | Line line = new Line(points[i], points[j]); 22 | addLine(lines, line); 23 | int cnt = countEquivalentLines(lines, line); 24 | if (cnt > bestCnt) { 25 | bestCnt = cnt; 26 | bestLine = line; 27 | } 28 | } 29 | } 30 | return bestLine; 31 | } 32 | 33 | private static int countEquivalentLines(HashMap> lines, Line line) { 34 | int cnt = 0; 35 | double key = floorToEps(line.slope); 36 | ArrayList linesOfSameKey = lines.get(key); 37 | if (linesOfSameKey != null) { 38 | for (Line l : linesOfSameKey) { 39 | if (line.equals(l)) ++cnt; 40 | } 41 | } 42 | linesOfSameKey = lines.get(key + EPSILON); 43 | if (linesOfSameKey != null) { 44 | for (Line l : linesOfSameKey) { 45 | if (line.equals(l)) ++cnt; 46 | } 47 | } 48 | linesOfSameKey = lines.get(key - EPSILON); 49 | if (linesOfSameKey != null) { 50 | for (Line l : linesOfSameKey) { 51 | if (line.equals(l)) ++cnt; 52 | } 53 | } 54 | return cnt; 55 | } 56 | 57 | private static void addLine(HashMap> lines, Line line) { 58 | double key = floorToEps(line.slope); 59 | if (!lines.containsKey(key)) { 60 | lines.put(key, new ArrayList()); 61 | } 62 | lines.get(key).add(line); 63 | } 64 | 65 | public static class Line { 66 | double slope, intercept, x; 67 | boolean vertical; 68 | public Line(Point p1, Point p2) { 69 | if (p1 == null || p2 == null) { 70 | throw new IllegalArgumentException("Points are null!"); 71 | } else if (isEquivalent(p1.x, p2.x)) { 72 | vertical = true; 73 | this.x = p1.x; 74 | } else { 75 | slope = (p1.y - p2.y) / (p1.x - p2.x); 76 | intercept = p1.y - slope * p1.x; 77 | } 78 | } 79 | 80 | @Override 81 | public boolean equals(Object o) { 82 | if (!(o instanceof Line)) return false; 83 | Line that = (Line) o; 84 | if (vertical) { 85 | return that.vertical && 86 | isEquivalent(x, that.x); 87 | } else { 88 | return isEquivalent(slope, that.slope) && 89 | isEquivalent(intercept, that.intercept); 90 | } 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | if (vertical) 96 | return "X = " + x; 97 | else if (isEquivalent(slope, 0)) 98 | return "Y = " + intercept; 99 | else 100 | return "Y = " + slope + "*X + " + intercept; 101 | } 102 | } 103 | 104 | public static class Point { 105 | double x, y; 106 | public Point(double x, double y) { 107 | this.x = x; 108 | this.y = y; 109 | } 110 | } 111 | 112 | private static double floorToEps(double a) { 113 | return ((int)(a / EPSILON)) * EPSILON; 114 | } 115 | 116 | private static boolean isEquivalent(double a, double b) { 117 | return Math.abs(a - b) < EPSILON; 118 | } 119 | 120 | //TEST---------------------------------- 121 | public static void main(String[] args) { 122 | Point[] points = { 123 | new Point(0, 1.11), 124 | new Point(0, 0), 125 | new Point(1, 1.11), 126 | new Point(1.11, 1.11), 127 | new Point(1.11, 1), 128 | }; 129 | println(findBestLine(points)); 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/chap07/Q7.java: -------------------------------------------------------------------------------- 1 | package chap07; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.LinkedList; 7 | 8 | /** 9 | * Design an algorithm to find the kth number such that the only 10 | * prime factors are 3, 5, and 7. 11 | */ 12 | public class Q7 { 13 | public static int findKthNum(int k) { 14 | if (k <= 0) return -1; 15 | int[] dp = new int[k]; 16 | dp[0] = 1; 17 | int i3 = 0, i5 = 0, i7 = 0; 18 | for (int i = 1; i < k; ++i) { 19 | dp[i] = Math.min(dp[i3] * 3, Math.min(dp[i5] * 5, dp[i7] * 7)); 20 | if (dp[i] == dp[i3] * 3) ++i3; 21 | if (dp[i] == dp[i5] * 5) ++i5; 22 | if (dp[i] == dp[i7] * 7) ++i7; 23 | } 24 | return dp[k - 1]; 25 | } 26 | 27 | public static int findKthNum2(int k) { 28 | if (k <= 0) return -1; 29 | int num = 1; 30 | ArrayList q = new ArrayList(); 31 | q.add(num); 32 | for (int i = 0; i < k; ++i) { 33 | num = removeMin(q); 34 | q.add(3 * num); 35 | q.add(5 * num); 36 | q.add(7 * num); 37 | } 38 | return num; 39 | } 40 | 41 | private static int removeMin(ArrayList q) { 42 | Integer min = Integer.MAX_VALUE; 43 | for (int n : q) { 44 | if (n < min) min = n; 45 | } 46 | while (q.contains(min)) { 47 | q.remove(min); 48 | } 49 | return min; 50 | } 51 | 52 | public static int findKthNum3(int k) { 53 | if (k <= 0) return -1; 54 | int num = 1; 55 | LinkedList q3 = new LinkedList(); 56 | LinkedList q5 = new LinkedList(); 57 | LinkedList q7 = new LinkedList(); 58 | q3.add(num); 59 | for (int i = 0; i < k; ++i) { 60 | int n3 = q3.isEmpty() ? Integer.MAX_VALUE : q3.peek(); 61 | int n5 = q5.isEmpty() ? Integer.MAX_VALUE : q5.peek(); 62 | int n7 = q7.isEmpty() ? Integer.MAX_VALUE : q7.peek(); 63 | num = Math.min(n3, Math.min(n5, n7)); 64 | if (num == n3) { 65 | q3.removeFirst(); 66 | q3.add(3 * num); 67 | q5.add(5 * num); 68 | q7.add(7 * num); 69 | } else if (num == n5) { 70 | q5.removeFirst(); 71 | q5.add(5 * num); 72 | q7.add(7 * num); 73 | } else if (num == n7) { 74 | q7.removeFirst(); 75 | q7.add(7 * num); 76 | } 77 | } 78 | return num; 79 | } 80 | 81 | //TEST---------------------------------- 82 | public static void main(String[] args) { 83 | for (int i = 1; i <= 20; ++i) { 84 | println(findKthNum(i) + " " + findKthNum2(i) + " " + findKthNum3(i)); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/chap08/Q10.java: -------------------------------------------------------------------------------- 1 | package chap08; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.LinkedList; 6 | 7 | /** 8 | * Design and implement a hash table which uses chaining (linked 9 | * lists) to handle collisions. 10 | */ 11 | public class Q10 { 12 | public static class Item { 13 | private K key; 14 | private V value; 15 | 16 | public Item(K key, V value) { 17 | this.key = key; 18 | this.value = value; 19 | } 20 | public void setKey(K key) { 21 | this.key = key; 22 | } 23 | public void setValue(V value) { 24 | this.value = value; 25 | } 26 | public K getKey() { 27 | return key; 28 | } 29 | public V getValue() { 30 | return value; 31 | } 32 | } 33 | 34 | public static class HashTable { 35 | private static final int BUCKETS_SIZE = 10; 36 | private LinkedList>[] buckets; 37 | 38 | @SuppressWarnings("unchecked") 39 | public HashTable() { 40 | buckets = new LinkedList[BUCKETS_SIZE]; 41 | } 42 | 43 | public int getHashCode(K key) { 44 | return key.toString().length() % BUCKETS_SIZE; 45 | } 46 | 47 | public void put(K key, V value) { 48 | if (key == null) return; 49 | int hash = getHashCode(key); 50 | if (buckets[hash] == null) { 51 | buckets[hash] = new LinkedList>(); 52 | } 53 | LinkedList> bucket = buckets[hash]; 54 | for (Item item : bucket) { 55 | if (item.getKey().equals(key)) { 56 | item.setValue(value); 57 | return; 58 | } 59 | } 60 | bucket.add(new Item(key, value)); 61 | } 62 | 63 | public V get(K key) { 64 | if (key == null) return null; 65 | int hash = getHashCode(key); 66 | LinkedList> bucket = buckets[hash]; 67 | if (bucket == null) return null; 68 | for (Item item : bucket) { 69 | if (item.getKey().equals(key)) return item.getValue(); 70 | } 71 | return null; 72 | } 73 | 74 | public boolean remove(K key) { 75 | if (key == null) return false; 76 | int hash = getHashCode(key); 77 | LinkedList> bucket = buckets[hash]; 78 | if (bucket == null) return false; 79 | for (Item item : bucket) { 80 | if (item.getKey().equals(key)) { 81 | bucket.remove(item); 82 | return true; 83 | } 84 | } 85 | return false; 86 | } 87 | 88 | public void printTable() { 89 | for (int i = 0; i < buckets.length; ++i) { 90 | LinkedList> bucket = buckets[i]; 91 | if (bucket == null) continue; 92 | print("[bucket " + i + "] "); 93 | for (Item item : bucket) { 94 | print(item.getKey() + ":" + item.getValue() + " "); 95 | } 96 | println(); 97 | } 98 | } 99 | } 100 | 101 | //TEST---------------------------------- 102 | public static void main(String[] args) { 103 | HashTable map = new HashTable(); 104 | map.put("cat", 1); 105 | map.put("dog", 2); 106 | map.put("fish", 2); 107 | map.put("tiger", 3); 108 | map.put("spiderman", 4); 109 | map.put("averylongtruck", 5); 110 | map.printTable(); 111 | println(map.get("none")); 112 | println(map.get("spiderman")); 113 | println(map.remove("none")); 114 | println(map.remove("spiderman")); 115 | println(map.get("spiderman")); 116 | map.printTable(); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/chap09/Q01.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * A child is running up a staircase with n steps, and can 7 | * hop either 1 step, 2 steps, or 3 steps at a time. Implement 8 | * a method to count how many possible ways the child can run 9 | * up the stairs. 10 | */ 11 | public class Q01 { 12 | // Naive: O(3^n) time, O(n) space 13 | public static int countWays(int n) { 14 | if (n < 0) return 0; 15 | if (n == 0) return 1; 16 | return countWays(n - 1) + countWays(n - 2) + countWays(n - 3); 17 | } 18 | 19 | // Memoization (top-down): O(n) time, O(n) space 20 | public static int countWaysMemo(int n) { 21 | return countWaysMemo(n, new int[n + 1]); 22 | } 23 | 24 | private static int countWaysMemo(int n, int[] cache) { 25 | if (n < 0) return 0; 26 | if (n == 0) return 1; 27 | if (cache[n] == 0) 28 | cache[n] = countWays(n - 1) + countWays(n - 2) + countWays(n - 3); 29 | return cache[n]; 30 | } 31 | 32 | // DP with rolling array (bottom-up): O(n) time, O(1) space 33 | public static int countWaysDP(int n) { 34 | if (n < 0) return 0; 35 | if (n == 0) return 1; 36 | if (n == 1) return 2; 37 | if (n == 2) return 4; 38 | 39 | int[] dp = new int[3]; 40 | dp[0] = 1; dp[1] = 2; dp[2] = 4; 41 | for (int i = 3; i < n; ++i) { 42 | dp[i%3] = dp[(i - 1)%3] + dp[(i - 2)%3] + dp[(i - 3)%3]; 43 | } 44 | return dp[(n - 1)%3]; 45 | } 46 | 47 | public static void countWaysPrinter(int n) { 48 | println(n + "-step stairs:"); 49 | if (n <= 0) { 50 | println("None!"); 51 | } else { 52 | println("countWays: " + countWays(n)); 53 | println("countWaysMemo: " + countWaysMemo(n)); 54 | println("countWaysDP: " + countWaysDP(n)); 55 | } 56 | println(); 57 | } 58 | 59 | //TEST---------------------------------- 60 | public static void main(String[] args) { 61 | countWaysPrinter(1); 62 | countWaysPrinter(10); 63 | countWaysPrinter(25); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/chap09/Q02.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.HashMap; 8 | 9 | /** 10 | * Imagine a robot sitting on the upper left comer of an X by Y 11 | * grid. The robot can only move in two directions: right and down. 12 | * How many possible paths are there for the robot to go from (0, 0) 13 | * to (X, Y)? 14 | * 15 | * Choose X from X + Y: C(X+Y, X) = (X+Y)!/(X!Y!) 16 | * 17 | * FOLLOW UP 18 | * Imagine certain spots are "off limits", such that the robot 19 | * cannot step on them. Design an algorithm to find a path for 20 | * the robot from the top left to the bottom right. 21 | */ 22 | public class Q02 { 23 | public static ArrayList findPath(int[][] map) { 24 | ArrayList path = new ArrayList(); 25 | findPath(map.length - 1, map[0].length - 1, map, path); 26 | return path; 27 | } 28 | 29 | private static boolean findPath(int x, int y, int[][] map, ArrayList path) { 30 | if (x < 0 || y < 0) return false; 31 | if (map[x][y] == 0) return false; 32 | Point p = new Point(x, y); 33 | if (x == 0 && y == 0) { 34 | path.add(p); 35 | return true; 36 | } 37 | boolean success = findPath(x - 1, y, map, path); 38 | if (!success) success = findPath(x, y - 1, map, path); 39 | if (success) path.add(p); 40 | return success; 41 | } 42 | 43 | public static ArrayList findPathDP(int[][] map) { 44 | ArrayList path = new ArrayList(); 45 | HashMap cache = new HashMap(); 46 | findPathDP(map.length - 1, map[0].length - 1, map, path, cache); 47 | return path; 48 | } 49 | 50 | private static boolean findPathDP(int x, int y, int[][] map, ArrayList path, HashMap cache) { 51 | if (x < 0 || y < 0) return false; 52 | if (map[x][y] == 0) return false; 53 | Point p = new Point(x, y); 54 | if (cache.containsKey(p)) return cache.get(p); 55 | if (x == 0 && y == 0) { 56 | path.add(p); 57 | return true; 58 | } 59 | boolean success = findPathDP(x - 1, y, map, path, cache); 60 | if (!success) success = findPathDP(x, y - 1, map, path, cache); 61 | if (success) path.add(p); 62 | cache.put(p, success); 63 | return success; 64 | } 65 | 66 | /** 67 | * FOLLOW UP 2 68 | * What if multiple paths are available? 69 | * Find all paths. 70 | */ 71 | public static ArrayList> findAllPaths(int[][] map) { 72 | ArrayList> result = new ArrayList>(); 73 | findAllPaths(map.length - 1, map[0].length - 1, map, new ArrayList(), result); 74 | return result; 75 | } 76 | 77 | // pass in an ArrayList as buffer 78 | @SuppressWarnings("unchecked") 79 | private static void findAllPaths(int x, int y, int[][] map, 80 | ArrayList path, ArrayList> result) { 81 | if (x < 0 || y < 0) return; 82 | if (map[x][y] == 0) return; 83 | Point p = new Point(x, y); 84 | path.add(0, p); 85 | if (x == 0 && y == 0) { 86 | result.add((ArrayList) path.clone()); 87 | } 88 | findAllPaths(x - 1, y, map, path, result); 89 | findAllPaths(x, y - 1, map, path, result); 90 | path.remove(p); 91 | } 92 | 93 | public static ArrayList> findAllPaths2(int[][] map) { 94 | ArrayList> result = new ArrayList>(); 95 | Point[] path = new Point[2 * map.length - 1]; 96 | findAllPaths2(map.length - 1, map[0].length - 1, map, path, path.length - 1, result); 97 | return result; 98 | } 99 | 100 | // pass in an Array as buffer 101 | private static void findAllPaths2(int x, int y, int[][] map, 102 | Point[] path, int index, ArrayList> result) { 103 | if (x < 0 || y < 0) return; 104 | if (map[x][y] == 0) return; 105 | Point p = new Point(x, y); 106 | path[index] = p; 107 | if (x == 0 && y == 0) { 108 | result.add(new ArrayList(Arrays.asList(path))); 109 | } 110 | findAllPaths2(x - 1, y, map, path, index - 1, result); 111 | findAllPaths2(x, y - 1, map, path, index - 1, result); 112 | } 113 | 114 | public static class Point { 115 | int x, y; 116 | public Point(int x, int y) { 117 | this.x = x; 118 | this.y = y; 119 | } 120 | public String toString() { 121 | return "(" + x + ", " + y + ")"; 122 | } 123 | public boolean equals(Object o) { 124 | if (!(o instanceof Point)) return false; 125 | Point that = (Point) o; 126 | return x == that.x && y == that.y; 127 | } 128 | public int hashCode() { 129 | return Integer.valueOf(x).hashCode() * 130 | Integer.valueOf(y).hashCode(); 131 | } 132 | } 133 | 134 | //TEST---------------------------------- 135 | public static void main(String[] args) { 136 | int[][] map = {{1,1,0,1}, 137 | {1,1,1,1}, 138 | {1,0,1,1}, 139 | {1,1,0,1}}; 140 | println(findPath(map)); 141 | println(findPathDP(map)); 142 | println(findAllPaths(map)); 143 | println(findAllPaths2(map)); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/chap09/Q03.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * A magic index in an array A[0...n] is defined to be an index 9 | * such that A[i] = i. Given a sorted array of distinct integers, 10 | * write a method to find a magic index, if one exists, in array A. 11 | * 12 | * FOLLOW UP 13 | * What if the values are not distinct? 14 | */ 15 | public class Q03 { 16 | // O(log n) time 17 | public static int getMagicIndex(int[] a) { 18 | if (a == null) return -1; 19 | return getMagicIndex(a, 0, a.length - 1); 20 | } 21 | 22 | private static int getMagicIndex(int[] a, int start, int end) { 23 | if (start > end) return -1; 24 | int mid = start + (end - start) / 2; 25 | if (a[mid] == mid) { 26 | return mid; 27 | } 28 | else if (a[mid] < mid) { 29 | return getMagicIndex(a, mid + 1, end); 30 | } 31 | else { 32 | return getMagicIndex(a, start, mid - 1); 33 | } 34 | } 35 | 36 | // worst case O(n) time, no better than a linear scan 37 | public static int getMagicIndexDup(int[] a) { 38 | if (a == null) return -1; 39 | return getMagicIndexDup(a, 0, a.length - 1); 40 | } 41 | 42 | private static int getMagicIndexDup(int[] a, int start, int end) { 43 | if (start > end) return -1; 44 | int mid = start + (end - start) / 2; 45 | if (a[mid] == mid) return mid; 46 | // search left 47 | int result = getMagicIndexDup(a, start, Math.min(mid - 1, a[mid])); 48 | // search right 49 | if (result == -1) { 50 | result = getMagicIndexDup(a, Math.max(mid + 1, a[mid]), end); 51 | } 52 | return result; 53 | } 54 | 55 | /** 56 | * FOLLOW UP 2 57 | * What if multiple indexes are satisfied? 58 | * Find all indexes. 59 | */ 60 | 61 | // worst case O(n) time, no better than a linear scan 62 | public static ArrayList getAllMagicIndexDup(int[] a) { 63 | ArrayList result = new ArrayList(); 64 | getAllMagicIndexDup(a, 0, a.length - 1, result); 65 | return result; 66 | } 67 | 68 | private static void getAllMagicIndexDup(int[] a, int start, int end, ArrayList result) { 69 | if (start > end) return; 70 | int mid = start + (end - start) / 2; 71 | if (a[mid] == mid) result.add(mid); 72 | // search left 73 | getAllMagicIndexDup(a, start, Math.min(mid - 1, a[mid]), result); 74 | // search right 75 | getAllMagicIndexDup(a, Math.max(mid + 1, a[mid]), end, result); 76 | } 77 | 78 | //TEST---------------------------------- 79 | public static void main(String[] args) { 80 | println(getMagicIndex(new int[] {-1, 0, 1, 3, 5, 7, 9})); 81 | println(getMagicIndexDup(new int[] {-1,0,2,2,2,2,3,4,6,9,11,12,13})); 82 | println(getMagicIndexDup(new int[] {-10,-5,2,2,2,3,4,7,9,12,13})); 83 | println(getAllMagicIndexDup(new int[] {-10,-5,2,2,2,3,4,7,9,12,13})); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/chap09/Q04.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.List; 8 | 9 | /** 10 | * Write a method to return all subsets of a set. 11 | */ 12 | public class Q04 { 13 | /* 14 | * Naive recursion: 15 | * Compute P(n-1), clone the results, and then add a(n) to each of these cloned sets. 16 | * O(2^n) time and space. 17 | */ 18 | public static ArrayList> getSubsetsNaive(List set) { 19 | if (set == null) return null; 20 | ArrayList> result = new ArrayList>(); 21 | if (set.isEmpty()) { 22 | result.add(new ArrayList()); 23 | return result; 24 | } 25 | ArrayList> lastSubsets = getSubsetsNaive(set.subList(1, set.size())); 26 | result.addAll(lastSubsets); 27 | for (ArrayList lastSubset : lastSubsets) { 28 | ArrayList subset = new ArrayList(lastSubset); 29 | subset.add(set.get(0)); 30 | result.add(subset); 31 | } 32 | return result; 33 | } 34 | 35 | /* 36 | * Better recursion: backtracking 37 | */ 38 | public static List> getSubsetsBacktrack(List set) { 39 | List> result = new ArrayList>(); 40 | getSubsetsBacktrack(set, 0, result, new ArrayList()); 41 | return result; 42 | } 43 | 44 | private static void getSubsetsBacktrack(List input, int index, List> result, List subset) { 45 | result.add(new ArrayList(subset)); 46 | for (int i = index; i < input.size(); ++i) { 47 | subset.add(input.get(i)); 48 | getSubsetsBacktrack(input, i + 1, result, subset); 49 | subset.remove(subset.size() - 1); 50 | } 51 | } 52 | 53 | /* 54 | * Bitmap: 55 | * Iterate through all numbers from 1 to 2^n and translate the binary representation 56 | * of the numbers into a set. 57 | * O(2^n) time and space. 58 | */ 59 | public static ArrayList> getSubsetsIterative(List set) { 60 | if (set == null) return null; 61 | ArrayList> result = new ArrayList>(); 62 | for (int bitmap = 0; bitmap < 1 << set.size(); ++bitmap) { 63 | result.add(getSubsetFromBitmap(set, bitmap)); 64 | } 65 | return result; 66 | } 67 | 68 | private static ArrayList getSubsetFromBitmap(List set, int bitmap) { 69 | ArrayList subset = new ArrayList(); 70 | int i = 0; 71 | while (bitmap > 0) { 72 | if ((bitmap & 1) != 0) subset.add(set.get(i)); 73 | bitmap >>= 1; 74 | ++i; 75 | } 76 | return subset; 77 | } 78 | 79 | //TEST---------------------------------- 80 | public static void main(String[] args) { 81 | Integer[] a = {1,3,5,7}; 82 | println(getSubsetsNaive(Arrays.asList(a))); 83 | println(getSubsetsBacktrack(Arrays.asList(a))); 84 | println(getSubsetsIterative(Arrays.asList(a))); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/chap09/Q05.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * Write a method to compute all permutations of a string. 9 | */ 10 | public class Q05 { 11 | /* 12 | * Naive recursion: 13 | * Solve for f(n - 1), and then push a(n) into every spot 14 | * in each of these strings. 15 | * O(n!) time. 16 | */ 17 | public static ArrayList getPermutations(String s) { 18 | if (s == null) return null; 19 | ArrayList result = new ArrayList(); 20 | // Even no need to have s.length()==1 base case 21 | if (s.isEmpty()) { 22 | result.add(s); 23 | return result; 24 | } 25 | ArrayList lastStrings = getPermutations(s.substring(1)); 26 | for (String lastString : lastStrings) { 27 | for (int i = 0; i <= lastString.length(); ++i) { 28 | result.add(lastString.substring(0, i) + 29 | s.charAt(0) + 30 | lastString.substring(i)); 31 | } 32 | } 33 | return result; 34 | } 35 | 36 | /* 37 | * Better recursion: backtracking 38 | */ 39 | public static ArrayList getPermutations2(String s) { 40 | if (s == null) return null; 41 | ArrayList result = new ArrayList(); 42 | permute(result, "", s.toCharArray()); 43 | return result; 44 | } 45 | 46 | private static void permute(ArrayList result, String curr, char[] s) { 47 | if (curr.length() == s.length) { 48 | result.add(curr); 49 | } else { 50 | for (int i = 0; i < s.length; ++i) { 51 | if (s[i] == '\0') continue; 52 | char ch = s[i]; 53 | s[i] = '\0'; 54 | permute(result, curr + ch, s); 55 | s[i] = ch; 56 | } 57 | } 58 | } 59 | 60 | //TEST---------------------------------- 61 | public static void main(String[] args) { 62 | println(getPermutations("ab12")); 63 | println(getPermutations2("ab12")); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/chap09/Q06.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.println; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashSet; 7 | 8 | /** 9 | * Implement an algorithm to print all valid (e.g., properly 10 | * opened and closed) combinations of n-pairs of parentheses. 11 | * 12 | * EXAMPLE 13 | * Input: 3 14 | * Output: ((())), (()()), (())(), ()(()), ()()() 15 | */ 16 | public class Q06 { 17 | public static HashSet getParens(int n) { 18 | if (n < 0) return null; 19 | HashSet result = new HashSet(); 20 | if (n == 0) { 21 | result.add(""); 22 | return result; 23 | } 24 | HashSet lastParens = getParens(n - 1); 25 | for (String parens : lastParens) { 26 | for (int i = 0; i <= parens.length(); ++i) { 27 | result.add(parens.substring(0, i) + 28 | "()" + 29 | parens.substring(i)); 30 | } 31 | } 32 | return result; 33 | } 34 | 35 | public static ArrayList getParens2(int n) { 36 | if (n < 0) return null; 37 | ArrayList result = new ArrayList(); 38 | addParens(n, n, new char[n * 2], 0, result); 39 | return result; 40 | } 41 | 42 | private static void addParens(int leftNum, int rightNum, char[] chars, int i, ArrayList parens) { 43 | if (leftNum == 0 && rightNum == 0) { 44 | parens.add(new String(chars)); 45 | } 46 | if (leftNum > 0) { 47 | chars[i] = '('; 48 | addParens(leftNum - 1, rightNum, chars, i + 1, parens); 49 | } 50 | if (rightNum > leftNum) { 51 | chars[i] = ')'; 52 | addParens(leftNum, rightNum - 1, chars, i + 1, parens); 53 | } 54 | } 55 | 56 | //TEST---------------------------------- 57 | public static void main(String[] args) { 58 | println(getParens(4)); 59 | println(getParens2(4)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/chap09/Q07.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Implement the "paint fill" function that one might see on 7 | * many image editing programs. That is, given a screen 8 | * (represented by a two-dimensional array of colors), a point, 9 | * and a new color, fill in the surrounding area until the color 10 | * changes from the original color. 11 | */ 12 | public class Q07 { 13 | public static void paintFill(Color[][] screen, int x, int y, Color newColor) { 14 | if (x < 0 || y < 0 || x > screen.length - 1 || y > screen[0].length - 1) return; 15 | if (screen == null || newColor == null || screen[x][y] == newColor) return; 16 | paintFill(screen, x, y, screen[x][y], newColor); 17 | } 18 | 19 | private static void paintFill(Color[][] screen, int x, int y, Color oldColor, Color newColor) { 20 | if (x < 0 || y < 0 || x > screen.length - 1 || y > screen[0].length - 1) return; 21 | if (screen[x][y] == oldColor) { 22 | screen[x][y] = newColor; 23 | paintFill(screen, x + 1, y, oldColor, newColor); 24 | paintFill(screen, x - 1, y, oldColor, newColor); 25 | paintFill(screen, x, y + 1, oldColor, newColor); 26 | paintFill(screen, x, y - 1, oldColor, newColor); 27 | } 28 | } 29 | 30 | enum Color {R, G, B} 31 | 32 | //TEST---------------------------------- 33 | public static void main(String[] args) { 34 | /* ______y 35 | * |RRGBR 36 | * |RGGGR 37 | * |RRGBG 38 | * |RBGGG 39 | * |GRGBG 40 | * x 41 | */ 42 | Color[][] screen = {{Color.R,Color.R,Color.G,Color.B,Color.R}, 43 | {Color.R,Color.G,Color.G,Color.G,Color.R}, 44 | {Color.R,Color.R,Color.G,Color.B,Color.G}, 45 | {Color.R,Color.B,Color.G,Color.G,Color.G}, 46 | {Color.G,Color.R,Color.G,Color.B,Color.G}}; 47 | printScreen(screen); 48 | paintFill(screen, 1, 1, Color.G); 49 | printScreen(screen); 50 | paintFill(screen, 100, 100, Color.G); 51 | printScreen(screen); 52 | paintFill(screen, 1, 1, Color.B); 53 | printScreen(screen); 54 | } 55 | 56 | private static void printScreen(Color[][] screen) { 57 | for (Color[] row : screen) { 58 | for (Color c : row) print(c); 59 | println(); 60 | } 61 | println(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/chap09/Q08.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given an infinite number of quarters (25 cents), dimes (10 7 | * cents), nickels (5 cents) and pennies (1 cent), write code 8 | * to calculate the number of ways of representing n cents. 9 | * 10 | * Good read 11 | * http://blog.csdn.net/fightforyourdream/article/details/16979395 12 | */ 13 | public class Q08 { 14 | /* 15 | * Get all combinations. 16 | * Pass an extra variable in each recursive call to direct 17 | * flow to avoid duplicate computation. 18 | */ 19 | private static int makeChange(int n, int coin) { 20 | if (n < 0) return 0; 21 | if (n == 0) return 1; 22 | int ways = 0; 23 | switch(coin) { 24 | case 25: ways += makeChange(n - 25, 25); 25 | case 10: ways += makeChange(n - 10, 10); 26 | case 5: ways += makeChange(n - 5, 5); 27 | case 1: ways += makeChange(n - 1, 1); 28 | } 29 | return ways; 30 | } 31 | 32 | public static int makeChange(int n) { 33 | if (n <= 0) return 0; 34 | return makeChange(n, 25); 35 | } 36 | 37 | /* 38 | * Yet another elegant and extensible implementation with 39 | * same principle as above. 40 | * Source: http://sunmingtao.blogspot.com/2014/01/coins.html 41 | */ 42 | private static final int[] COINS = {1, 5, 10, 25}; 43 | private static int makeChange2(int n, int index) { 44 | if (n < 0) return 0; 45 | if (n == 0) return 1; 46 | int ways = 0; 47 | for (int i = 0; i <= index; ++i) { 48 | ways += makeChange2(n - COINS[i], i); 49 | } 50 | return ways; 51 | } 52 | 53 | public static int makeChange2(int n) { 54 | if (n <= 0) return 0; 55 | return makeChange2(n, 3); 56 | } 57 | 58 | /* 59 | * This implementation is WRONG because we get all permutations. 60 | */ 61 | public static int makeChangeWrong(int n) { 62 | if (n < 0) return 0; 63 | if (n == 0) return 1; 64 | return makeChangeWrong(n - 25) + 65 | makeChangeWrong(n - 10) + 66 | makeChangeWrong(n - 5) + 67 | makeChangeWrong(n - 1); 68 | } 69 | 70 | //TEST---------------------------------- 71 | public static void main(String[] args) { 72 | println(makeChange(20)); 73 | println(makeChange2(20)); 74 | println(makeChangeWrong(20)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/chap09/Q09.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * Write an algorithm to print all ways of arranging eight queens 9 | * on an 8x8 chess board so that none of them share the same row, 10 | * column or diagonal. In this case, "diagonal" means all diagonals, 11 | * not just the two that bisect the board. 12 | */ 13 | public class Q09 { 14 | public static ArrayList placeQueens(int gridSize) { 15 | ArrayList result = new ArrayList(); 16 | placeQueens(0, new int[gridSize], result, gridSize); 17 | return result; 18 | } 19 | 20 | private static void placeQueens(int row, int[] solution, ArrayList solutions, int gridSize) { 21 | if (row == gridSize) { 22 | solutions.add(solution.clone()); 23 | return; 24 | } 25 | for (int col = 0; col < gridSize; ++col) { 26 | if (canPlace(row, col, solution)) { 27 | solution[row] = col; 28 | placeQueens(row + 1, solution, solutions, gridSize); 29 | } 30 | } 31 | } 32 | 33 | /* 34 | * FOLLOW UP 35 | * What if you only need to count the number of solutions? 36 | */ 37 | public static int placeQueensNum(int gridSize) { 38 | return placeQueensNum(0, new int[gridSize], gridSize); 39 | } 40 | 41 | private static int placeQueensNum(int row, int[] solution, int gridSize) { 42 | if (row == gridSize) { 43 | return 1; 44 | } 45 | int num = 0; 46 | for (int col = 0; col < gridSize; ++col) { 47 | if (canPlace(row, col, solution)) { 48 | solution[row] = col; 49 | num += placeQueensNum(row + 1, solution, gridSize); 50 | } 51 | } 52 | return num; 53 | } 54 | 55 | private static boolean canPlace(int row, int col, int[] solution) { 56 | for (int prevRow = 0; prevRow < row; ++prevRow) { 57 | if (col == solution[prevRow]) return false; 58 | if (row - prevRow == Math.abs(col - solution[prevRow])) return false; 59 | } 60 | return true; 61 | } 62 | 63 | //TEST---------------------------------- 64 | public static void main(String[] args) { 65 | println("Solutions:"); 66 | printSolution(placeQueens(8)); 67 | println("\nNumber of solutions:"); 68 | println(placeQueensNum(8)); 69 | } 70 | 71 | private static void printSolution(ArrayList solutions) { 72 | for (int[] solution : solutions) { 73 | for (int i : solution) print(i + " "); 74 | println(); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/chap09/Q10.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * You have a stack of n boxes, with widths w, heights h and 10 | * depths d. The boxes cannot be rotated and can only be stacked 11 | * on top of one another if each box in the stack is strictly 12 | * larger than the box above it in width, height, and depth. 13 | * Implement a method to build the tallest stack possible, where 14 | * the height of a stack is the sum of the heights of each box. 15 | */ 16 | public class Q10 { 17 | /* 18 | * Also see http://www.geeksforgeeks.org/dynamic-programming-set-21-box-stacking-problem/ 19 | * for a generalized version of box stacking problem. 20 | */ 21 | public static ArrayList buildTallestStack(Box[] boxes) { 22 | if (boxes == null) return null; 23 | return buildTallestStack(boxes, null); 24 | } 25 | 26 | private static ArrayList buildTallestStack(Box[] boxes, Box bottom) { 27 | int maxHeight = 0; 28 | ArrayList maxStack = null; 29 | for (Box box : boxes) { 30 | if (box.canPlaceAbove(bottom)) { 31 | ArrayList boxStack = buildTallestStack(boxes, box); 32 | int height = getStackHeight(boxStack); 33 | if (height > maxHeight) { 34 | maxHeight = height; 35 | maxStack = boxStack; 36 | } 37 | } 38 | } 39 | if (maxStack == null) maxStack = new ArrayList(); 40 | if (bottom != null) maxStack.add(0, bottom); 41 | return maxStack; 42 | } 43 | 44 | private static int getStackHeight(List boxes) { 45 | int height = 0; 46 | for (Box b : boxes) height += b.height; 47 | return height; 48 | } 49 | 50 | public static class Box { 51 | private int width, length, height; 52 | public Box(int w, int l, int h) { 53 | width = w; 54 | length = l; 55 | height = h; 56 | } 57 | public boolean canPlaceAbove(Box b) { 58 | return b == null || 59 | (this.width < b.width && 60 | this.length < b.length && 61 | this.height < b.height); 62 | } 63 | public String toString() { 64 | return "(" + width + ", " + length + ", " + height + ")"; 65 | } 66 | } 67 | 68 | //TEST---------------------------------- 69 | public static void main(String[] args) { 70 | Box[] boxes = { 71 | new Box(1, 7, 4), 72 | new Box(2, 6, 9), 73 | new Box(4, 9, 6), 74 | new Box(10, 12, 8), 75 | new Box(6, 2, 5), 76 | new Box(3, 8, 5), 77 | new Box(5, 7, 7), 78 | new Box(2, 10, 16), 79 | new Box(12, 15, 9), 80 | }; 81 | println(buildTallestStack(boxes)); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/chap09/Q11.java: -------------------------------------------------------------------------------- 1 | package chap09; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * Given a boolean expression consisting of the symbols (0, 1, &, 9 | * /, and ^) and a desired boolean result value result, implement 10 | * a function to count the number of ways of parenthesizing the 11 | * expression such that it evaluates to result. 12 | */ 13 | public class Q11 { 14 | /* 15 | * SOLUTION 16 | * Iterate through all operators, dividing the expression into 17 | * left/right subexpressions. Evaluate left/right subexpressions 18 | * recursively, according to &, |, ^ rules. 19 | */ 20 | public static int count(String exp, boolean res) { 21 | return countDP(exp, res, 0, exp.length() - 1, new HashMap()); 22 | } 23 | 24 | private static int countDP(String expression, boolean result, int start, int end, HashMap cache) { 25 | String key = "" + result + start + end; 26 | if (cache.containsKey(key)) return cache.get(key); 27 | // Base case: single value evaluation 28 | if (start == end) { 29 | char operand = expression.charAt(start); 30 | if (result) { 31 | if (operand == '1') return 1; 32 | else if (operand == '0') return 0; 33 | else throw new IllegalArgumentException("Invalid operand!"); 34 | } else { 35 | if (operand == '0') return 1; 36 | else if (operand == '1') return 0; 37 | else throw new IllegalArgumentException("Invalid operand!"); 38 | } 39 | } 40 | // Recursive case: subexpression evaluation 41 | int cnt = 0; 42 | if (result) { 43 | for (int i = start + 1; i < end; i += 2) { 44 | char operator = expression.charAt(i); 45 | if (operator == '&') { 46 | cnt += countDP(expression, true, start, i - 1, cache) * countDP(expression, true, i + 1, end, cache); 47 | } else if (operator == '|') { 48 | cnt += countDP(expression, true, start, i - 1, cache) * countDP(expression, false, i + 1, end, cache); 49 | cnt += countDP(expression, false, start, i - 1, cache) * countDP(expression, true, i + 1, end, cache); 50 | cnt += countDP(expression, true, start, i - 1, cache) * countDP(expression, true, i + 1, end, cache); 51 | } else if (operator == '^') { 52 | cnt += countDP(expression, true, start, i - 1, cache) * countDP(expression, false, i + 1, end, cache); 53 | cnt += countDP(expression, false, start, i - 1, cache) * countDP(expression, true, i + 1, end, cache); 54 | } else { 55 | throw new IllegalArgumentException("Invalid operator!"); 56 | } 57 | } 58 | } else { 59 | for (int i = start + 1; i < end; i += 2) { 60 | char operator = expression.charAt(i); 61 | if (operator == '&') { 62 | cnt += countDP(expression, false, start, i - 1, cache) * countDP(expression, false, i + 1, end, cache); 63 | cnt += countDP(expression, false, start, i - 1, cache) * countDP(expression, true, i + 1, end, cache); 64 | cnt += countDP(expression, true, start, i - 1, cache) * countDP(expression, false, i + 1, end, cache); 65 | } else if (operator == '|') { 66 | cnt += countDP(expression, false, start, i - 1, cache) * countDP(expression, false, i + 1, end, cache); 67 | } else if (operator == '^') { 68 | cnt += countDP(expression, true, start, i - 1, cache) * countDP(expression, true, i + 1, end, cache); 69 | cnt += countDP(expression, false, start, i - 1, cache) * countDP(expression, false, i + 1, end, cache); 70 | } else { 71 | throw new IllegalArgumentException("Invalid operator!"); 72 | } 73 | } 74 | } 75 | cache.put(key, cnt); 76 | return cnt; 77 | } 78 | 79 | //TEST---------------------------------- 80 | public static void main(String[] args) { 81 | println(count("1^0|1",true)); 82 | println(count("1^0&1|0&1^0&1|0^1|1|0&0",true)); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/chap11/Q1.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * You are given two sorted arrays, A and B, where A has a large 7 | * enough buffer at the end to hold B. Write a method to merge B 8 | * into A in sorted order. 9 | */ 10 | public class Q1 { 11 | public static void merge(int[] a, int[] b, int lastA) { 12 | if (a == null || b == null) return; 13 | int indexA = lastA + b.length; 14 | int lastB = b.length - 1; 15 | while (lastA >= 0 && lastB >= 0) { 16 | if (a[lastA] >= b[lastB]) { 17 | a[indexA] = a[lastA]; 18 | --lastA; 19 | } else { 20 | a[indexA] = b[lastB]; 21 | --lastB; 22 | } 23 | --indexA; 24 | } 25 | while (lastB >= 0) { 26 | a[indexA] = b[lastB]; 27 | --indexA; 28 | --lastB; 29 | } 30 | } 31 | 32 | //TEST---------------------------------- 33 | public static void main(String[] args) { 34 | int[] a = {1,3,4,5,6,0,0,0,0,0,0,0,0,0,0}; 35 | int[] b = {2,3,3,7}; 36 | merge(a, b, 4); 37 | printArray(a); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/chap11/Q2.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Arrays; 6 | import java.util.HashMap; 7 | import java.util.ArrayList; 8 | 9 | /** 10 | * Write a method to sort an array of strings so that all the 11 | * anagrams are next to each other. 12 | */ 13 | public class Q2 { 14 | public static void sortStrings(String[] strings) { 15 | HashMap> map = new HashMap>(); 16 | for (String s: strings) { 17 | char[] chars = s.toCharArray(); 18 | Arrays.sort(chars); 19 | String key = String.valueOf(chars); 20 | if (!map.containsKey(key)) { 21 | map.put(key, new ArrayList()); 22 | } 23 | map.get(key).add(s); 24 | } 25 | int i = 0; 26 | for (String key : map.keySet()) { 27 | for (String s : map.get(key)) { 28 | strings[i++] = s; 29 | } 30 | } 31 | } 32 | 33 | //TEST---------------------------------- 34 | public static void main(String[] args) { 35 | String[] strings = {"acb", "ijh", "abc", "iop", "cab", "pio", "hij"}; 36 | sortStrings(strings); 37 | printArray(strings); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/chap11/Q3.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given a sorted array of n integers that has been rotated an 7 | * unknown number of times, write code to find an element in 8 | * the array. You may assume that the array was originally 9 | * sorted in increasing order. 10 | */ 11 | public class Q3 { 12 | public static int search(int[] a, int x) { 13 | if (a == null) return -1; 14 | return search(a, x, 0, a.length - 1); 15 | } 16 | 17 | // worst case is O(n) time, no better than a linear scan 18 | private static int search(int[] a, int x, int low, int high) { 19 | if (low > high) return -1; 20 | int mid = low + (high - low) / 2; 21 | if (a[mid] == x) return mid; 22 | // left half is sorted 23 | if (a[low] < a[mid]) { 24 | if (x >= a[low] && x < a[mid]) { 25 | return search(a, x, low, mid - 1); 26 | } else { 27 | return search(a, x, mid + 1, high); 28 | } 29 | // right half sorted 30 | } else if (a[low] > a[mid]) { 31 | if (x > a[mid] && x <= a[high]) { 32 | return search(a, x, mid + 1, high); 33 | } else { 34 | return search(a, x, low, mid - 1); 35 | } 36 | } else { 37 | // left half must be all repeats 38 | if (a[mid] != a[high]) { 39 | return search(a, x, mid + 1, high); 40 | // no special pattern is found, so brute force 41 | } else { 42 | int result = search(a, x, low, mid - 1); 43 | if (result == -1) 44 | result = search(a, x, mid + 1,high); 45 | return result; 46 | } 47 | } 48 | } 49 | 50 | //TEST---------------------------------- 51 | public static void main(String[] args) { 52 | println(search(new int[] {2,2,2,2,3,4,1}, 1)); 53 | println(search(new int[] {1,1,1,1,1,1,1,0,1,1,1,1}, 0)); 54 | println(search(new int[] {1,1,1,2,1,1,1,1,1,1,1,1}, 2)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/chap11/Q4.txt: -------------------------------------------------------------------------------- 1 | Imagine you have a 20 GB file with one string per line. Explain how you would sort 2 | the file. 3 | 4 | SOLUTION 5 | 6 | Divide the file into N chunks which are x megabytes each, where x is the amount of 7 | memory we have available. Each chunk is sorted separately and then saved back to the 8 | file system. Once all the chunks are sorted, we then merge the chunks according to the 9 | following algorithm: 10 | 11 | 1. Divide your memory into (N+1) parts. First N parts are used to read data from N chunks, 12 | the last one is used as a buffer. 13 | 2. Load data to fill the first N data parts from N chunks respectively, perform an N-way 14 | merge sort to the buffer. 15 | 3. While any data part is not empty, perform sort to the buffer. 16 | 4. If any data part is empty, load new content from the corresponding chunk. 17 | 5. If the buffer is full, write buffer to the disk as output file, clear buffer. 18 | 6. Repeat step 4-5 until all N chunks and buffer are empty. 19 | 20 | At the end, we have output that is fully sorted on the disk. 21 | This algorithm is known as *external sort*. 22 | -------------------------------------------------------------------------------- /src/chap11/Q5.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given a sorted array of strings which is interspersed with 7 | * empty strings, write a method to find the location of a 8 | * given string. 9 | */ 10 | public class Q5 { 11 | public static int search(String[] strings, String s) { 12 | if (strings == null || s == null) return -1; 13 | return search(strings, s, 0, strings.length - 1); 14 | } 15 | 16 | // worst case is O(n) time, no better than a linear scan 17 | private static int search(String[] strings, String s, int low, int high) { 18 | if (low > high) return -1; 19 | int mid = low + (high - low) / 2; 20 | if (strings[mid].isEmpty()) { 21 | int left = mid - 1, right = mid + 1; 22 | // If strings[mid] is empty, find closest non-empty string. 23 | while (true) { 24 | if (left < low && right > high) 25 | return -1; 26 | if (left >= low && !strings[left].isEmpty()) { 27 | mid = left; 28 | break; 29 | } 30 | if (right <= high && !strings[right].isEmpty()) { 31 | mid = right; 32 | break; 33 | } 34 | --left; 35 | ++right; 36 | } 37 | } 38 | if (strings[mid].equals(s)) 39 | return mid; 40 | else if (strings[mid].compareTo(s) < 0) 41 | return search(strings, s, mid + 1, high); 42 | else 43 | return search(strings, s, low, mid - 1); 44 | } 45 | 46 | //TEST---------------------------------- 47 | public static void main(String[] args) { 48 | String[] strings = {"","","a","","","","b"}; 49 | println(search(strings, "a")); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/chap11/Q6.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given an M x N matrix in which each row and each column 7 | * is sorted in ascending order, write a method to find an 8 | * element. 9 | */ 10 | public class Q6 { 11 | // returns index (row, column) 12 | public static int[] search(int[][] m, int x) { 13 | if (m == null) return null; 14 | int i = 0, j = m[0].length - 1; 15 | while (i <= m.length - 1 && j >= 0) { 16 | if (m[i][j] == x) return new int[] {i, j}; 17 | else if (m[i][j] > x) --j; 18 | else ++i; 19 | } 20 | return new int[] {-1, -1}; 21 | } 22 | 23 | //TEST---------------------------------- 24 | public static void main(String[] args) { 25 | int[][] m = {{15,20,40, 85}, 26 | {20,35,80, 95}, 27 | {30,55,95, 105}, 28 | {40,80,100,120}}; 29 | printArray(search(m, 55)); 30 | printArray(search(m, 121)); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/chap11/Q7.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Collections; 8 | import java.util.List; 9 | 10 | /** 11 | * A circus is designing a tower routine consisting of people 12 | * standing atop one another's shoulders. For practical and 13 | * aesthetic reasons, each person must be both shorter and 14 | * lighter than the person below him or her. Given the heights 15 | * and weights of each person in the circus, write a method 16 | * to compute the largest possible number of people in such 17 | * a tower. 18 | * 19 | * EXAMPLE 20 | * Input (height, weight): 21 | * (65, 100) (70, 150) (56, 90) (75, 190) (60, 95) (68, 110) 22 | * Output: 23 | * The longest tower is length 6 and includes from top to bottom: 24 | * (56, 90) (60,95) (65, 100) (68, 110) (70, 150) (75, 190) 25 | */ 26 | public class Q7 { 27 | //treat it as a box-stacking problem 28 | public static ArrayList findHighestTower(List persons) { 29 | if (persons == null) return null; 30 | return findHighestTower(persons, null); 31 | } 32 | 33 | private static ArrayList findHighestTower(List persons, Person bottom) { 34 | int maxNum = 0; 35 | ArrayList maxTower = null; 36 | for (Person p : persons) { 37 | if (p.canStandAbove(bottom)) { 38 | ArrayList tower = findHighestTower(persons, p); 39 | int num = tower.size(); 40 | if (num > maxNum) { 41 | maxNum = num; 42 | maxTower = tower; 43 | } 44 | } 45 | } 46 | if (maxTower == null) maxTower = new ArrayList(); 47 | if (bottom != null) maxTower.add(bottom); 48 | return new ArrayList(maxTower); 49 | } 50 | 51 | //treat it as a longest-increasing-subsequence (LIS) problem 52 | public static ArrayList findHighestTower2(List persons) { 53 | if (persons == null) return null; 54 | Collections.sort(persons); 55 | 56 | ArrayList[] solutions = new ArrayList[persons.size()]; 57 | getLIS(persons, solutions, 0); 58 | 59 | ArrayList bestSolution = new ArrayList(); 60 | for (ArrayList solution : solutions) { 61 | if (solution.size() > bestSolution.size()) 62 | bestSolution = solution; 63 | } 64 | return bestSolution; 65 | } 66 | 67 | private static void getLIS(List persons, ArrayList[] solutions, int index) { 68 | if (index > persons.size() - 1) return; 69 | ArrayList bestSolution = new ArrayList(); 70 | Person current = persons.get(index); 71 | for (int i = 0; i < index; ++i) { 72 | if (persons.get(i).weight < current.weight) { 73 | if (solutions[i] != null & solutions[i].size() > bestSolution.size()) { 74 | bestSolution = solutions[i]; 75 | } 76 | } 77 | } 78 | ArrayList newSolution = new ArrayList(bestSolution); 79 | newSolution.add(current); 80 | solutions[index] = newSolution; 81 | getLIS(persons, solutions, index + 1); 82 | } 83 | 84 | private static class Person implements Comparable { 85 | int height, weight; 86 | public Person(int h, int w) { 87 | height = h; 88 | weight = w; 89 | } 90 | private boolean canStandAbove(Person that) { 91 | return that == null || 92 | (height < that.height && 93 | weight < that.weight); 94 | } 95 | public String toString() { 96 | return "(" + height + ", " + weight + ")"; 97 | } 98 | public int compareTo(Object o) { 99 | Person that = (Person) o; 100 | return height != that.height ? 101 | ((Integer) height).compareTo(that.height) : 102 | ((Integer) weight).compareTo(that.weight); 103 | } 104 | } 105 | 106 | //TEST---------------------------------- 107 | public static void main(String[] args) { 108 | Person[] persons = { 109 | new Person(56,94), 110 | new Person(60,95), 111 | new Person(65,100), 112 | new Person(68,93), 113 | new Person(70,150), 114 | new Person(75,200), 115 | new Person(75,100), 116 | new Person(76,190), 117 | new Person(76,220), 118 | }; 119 | List list = Arrays.asList(persons); 120 | Collections.shuffle(list); 121 | println(findHighestTower(list)); 122 | println(findHighestTower2(list)); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /src/chap11/Q8.java: -------------------------------------------------------------------------------- 1 | package chap11; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Imagine you are reading in a stream of integers. Periodically, 7 | * you wish to be able to look up the rank of a number x (the 8 | * number of values less than or equal to x). Implement the 9 | * data structures and algorithms to support these operations. 10 | * That is, implement the method track(int x), which is called 11 | * when each number is generated, and the method 12 | * getRankOfNumber(int x), which returns the number of values 13 | * less than or equal to x (not including x itself). 14 | * 15 | * EXAMPLE 16 | * Stream (in order of appearance): 5, 1, 4, 4, 5, 9, 7, 13, 3 17 | * getRankOfNumber(l) = 0 18 | * getRankOfNumber(3) = 1 19 | * getRankOfNumber(4) = 3 20 | */ 21 | public class Q8 { 22 | public static void track(int x) { 23 | if (root == null) root = new NodeWithRank(x); 24 | else track(x, root); 25 | } 26 | 27 | private static void track(int x, NodeWithRank n) { 28 | NodeWithRank newNode = new NodeWithRank(x); 29 | if (x <= n.value) { 30 | ++n.leftSize; 31 | if (n.left == null) { 32 | n.left = newNode; 33 | } else { 34 | track(x, n.left); 35 | } 36 | } else { 37 | if (n.right == null) { 38 | n.right = newNode; 39 | } else { 40 | track(x, n.right); 41 | } 42 | } 43 | } 44 | 45 | public static int getRankOfNumber(int x) { 46 | if (root == null) return -1; 47 | return getRankOfNumber(x, root); 48 | } 49 | 50 | private static int getRankOfNumber(int x, NodeWithRank n) { 51 | if (n == null) { 52 | return -1; 53 | } else if (x == n.value) { 54 | return n.leftSize; 55 | } else if (x <= n.value) { 56 | int leftRank = getRankOfNumber(x, n.left); 57 | return leftRank == -1 ? -1 : leftRank; 58 | } else { 59 | int rightRank = getRankOfNumber(x, n.right); 60 | return rightRank == -1 ? -1 : n.leftSize + 1 + rightRank; 61 | } 62 | } 63 | 64 | private static NodeWithRank root = null; 65 | 66 | private static class NodeWithRank { 67 | int value; 68 | int leftSize = 0; 69 | NodeWithRank left = null; 70 | NodeWithRank right = null; 71 | public NodeWithRank(int v) { 72 | value = v; 73 | } 74 | } 75 | 76 | //TEST---------------------------------- 77 | public static void main(String[] args) { 78 | println(getRankOfNumber(1)); 79 | 80 | track(5); track(1); track(4); track(4); track(4); 81 | track(5); track(9); track(7); track(13); track(3); 82 | 83 | println(getRankOfNumber(1)); 84 | println(getRankOfNumber(3)); 85 | println(getRankOfNumber(4)); 86 | println(getRankOfNumber(13)); 87 | println(getRankOfNumber(200)); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/chap14/Q6.java: -------------------------------------------------------------------------------- 1 | package chap14; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Iterator; 6 | 7 | /** 8 | * Implement a Circular Array class that supports an array-like 9 | * data structure which can be efficiently rotated. The class 10 | * should use a generic type, and should support iteration via 11 | * the standard for (Obj o : circuLarArray) notation. 12 | */ 13 | public class Q6 { 14 | public static class CircularArray implements Iterable { 15 | private T[] array; 16 | private int head; 17 | public CircularArray(int size) { 18 | array = (T[]) new Object[size]; 19 | head = 0; 20 | } 21 | /* n > 0: rotate left; n < 0: rotate right */ 22 | public void rotate(int n) { 23 | head = shift(n); 24 | } 25 | public T get(int index) { 26 | if (index < 0 || index >= array.length) 27 | throw new IllegalArgumentException("Invalid index!"); 28 | return array[shift(index)]; 29 | } 30 | public void set(int index, T value) { 31 | if (index < 0 || index >= array.length) 32 | throw new IllegalArgumentException("Invalid index!"); 33 | array[shift(index)] = value; 34 | } 35 | private int shift(int index) { 36 | int i = (head + index) % array.length; 37 | if (i < 0) i += array.length; 38 | return i; 39 | } 40 | @Override 41 | public Iterator iterator() { 42 | return new CircularArrayIterator(); 43 | } 44 | 45 | public class CircularArrayIterator implements Iterator { 46 | private int current = 0; 47 | @Override 48 | public boolean hasNext() { 49 | return current <= array.length - 1; 50 | } 51 | @Override 52 | public I next() { 53 | return (I) get(current++); 54 | } 55 | @Override 56 | public void remove() { 57 | throw new UnsupportedOperationException(); 58 | } 59 | } 60 | } 61 | 62 | 63 | //TEST---------------------------------- 64 | public static void main(String[] args) { 65 | CircularArray array = new CircularArray(8); 66 | array.set(0, 10); 67 | array.set(1, 20); 68 | array.set(3, 40); 69 | printCircularArray(array); 70 | array.rotate(1); 71 | printCircularArray(array); 72 | array.rotate(-202); 73 | printCircularArray(array); 74 | } 75 | 76 | private static void printCircularArray(CircularArray array) { 77 | for (Integer n : array) { 78 | print(n + " "); 79 | } 80 | println(); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/chap17/Q01.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write a function to swap a number in place (that is, without 7 | * temporary variables). 8 | */ 9 | public class Q01 { 10 | public static int[] swap(int a, int b) { 11 | a = a - b; // diff = a - b 12 | b = b + a; // now b is b + diff, which is a 13 | a = b - a; // now a is a - diff, which is b 14 | return new int[] {a, b}; 15 | } 16 | 17 | /* 18 | * Fact: 19 | * if diff = a XOR b, then 20 | * b is a XOR diff, 21 | * a is b XOR diff. 22 | */ 23 | public static int[] swap2(int a, int b) { 24 | a = a ^ b; // diff = a XOR b 25 | b = b ^ a; // now b is b XOR diff, which is a 26 | a = b ^ a; // now a is a XOR diff, which is b 27 | return new int[] {a, b}; 28 | } 29 | 30 | //TEST---------------------------------- 31 | public static void main(String[] args) { 32 | int a = 10, b = 55; 33 | printfln("a: %d, b: %d", a, b); 34 | int[] result = swap(a, b); 35 | printfln("a: %d, b: %d", result[0], result[1]); 36 | result = swap2(a, b); 37 | printfln("a: %d, b: %d", result[0], result[1]); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/chap17/Q02.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Design an algorithm to figure out if someone has won a 7 | * game of tic-tac-toe. 8 | */ 9 | public class Q02 { 10 | /* 11 | * N * N board 12 | * Returns 0 if 'X' wins, 1 if 'O' wins, -1 if tie. 13 | */ 14 | public static int win(int[][] board) { 15 | if (board == null) 16 | throw new IllegalArgumentException("Invalid board!"); 17 | int n = board.length; 18 | for (int i = 0; i < n; ++i) { 19 | // check row 20 | int shape = board[i][0]; 21 | if (shape != -1) { 22 | for (int j = 0; j < n; ++j) { 23 | if (board[i][j] != shape) break; 24 | if (j == n - 1) return shape; 25 | } 26 | } 27 | // check column 28 | shape = board[0][i]; 29 | if (shape != -1) { 30 | for (int j = 0; j < n; ++j) { 31 | if (board[j][i] != shape) break; 32 | if (j == n - 1) return shape; 33 | } 34 | } 35 | } 36 | // check diagonals 37 | int shape = board[0][0]; 38 | if (shape != -1) { 39 | for (int i = 0; i < n; ++i) { 40 | if (board[i][i] != shape) break; 41 | if (i == n - 1) return shape; 42 | } 43 | } 44 | shape = board[0][n - 1]; 45 | if (shape != -1) { 46 | for (int i = 0; i < n; ++i) { 47 | if (board[i][n - 1 - i] != shape) break; 48 | if (i == n - 1) return shape; 49 | } 50 | } 51 | return -1; 52 | } 53 | 54 | //TEST---------------------------------- 55 | public static void main(String[] args) { 56 | int[][] board = {{1,-1,-1, 0, 1}, 57 | {0, 1, 1, 0, -1}, 58 | {0,-1, 1, 0, -1}, 59 | {1, 1, 1, 0, 1}, 60 | {1,-1,-1, 0, 1}}; 61 | println(win(board)); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/chap17/Q03.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write an algorithm which computes the number of trailing 7 | * zeros in n factorial. 8 | * 9 | * SOLUTION 10 | * Simply count the number of 5 factors. 11 | * A 10 factor results in a trailing 0. 10 = 2*5, and there 12 | * are always more 2s than 5s. So counting 5s is sufficient. 13 | */ 14 | public class Q03 { 15 | public static int countFactZeros(int n) { 16 | if (n < 0) return -1; 17 | int cnt = 0; 18 | for (int i = 5; i <= n; i += 5) { 19 | cnt += countFiveFactors(i); 20 | } 21 | return cnt; 22 | } 23 | 24 | private static int countFiveFactors(int n) { 25 | int cnt = 0; 26 | while (n % 5 == 0) { 27 | ++cnt; 28 | n /= 5; 29 | } 30 | return cnt; 31 | } 32 | 33 | public static int countFactZeros2(int n) { 34 | if (n < 0) return -1; 35 | int cnt = 0; 36 | while (n > 0) { 37 | cnt += n / 5; 38 | n /= 5; 39 | } 40 | return cnt; 41 | } 42 | 43 | //TEST---------------------------------- 44 | public static void main(String[] args) { 45 | println(countFactZeros(5) + " " + countFactZeros2(5)); 46 | println(countFactZeros(260) + " " + countFactZeros2(260)); 47 | println(countFactZeros(1808548329) + " " + countFactZeros2(1808548329)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/chap17/Q04.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write a method which finds the maximum of two numbers. 7 | * You should not use if-else or any other comparison operator. 8 | * 9 | * SOLUTION 10 | * if-else can be translated to: 11 | * RESULT = EXPR_1 * COND + EXPR_2 * flip(COND), where value 1 (0) 12 | * in COND represents true (false). 13 | * 14 | * Signedness of an integer can be translated to: (n >> 31) & 1 15 | */ 16 | public class Q04 { 17 | public static int max1(int a, int b) { 18 | int k = sign(a - b); 19 | return a * k + b * flip(k); 20 | } 21 | 22 | // Returns 1 if positive, 0 otherwise 23 | public static int sign(int n) { 24 | // Check most significant bit: neg -> 1, pos -> 0 25 | return flip((n >> 31) & 1); 26 | } 27 | 28 | public static int flip(int i) { 29 | return 1 ^ i; 30 | } 31 | 32 | /* 33 | * Consider overflow of a - b 34 | */ 35 | public static int max2(int a, int b) { 36 | int cond1 = sign(a) ^ sign(b); 37 | /* 38 | * If A and B have different signs, use sign of A to 39 | * indicate return max; otherwise fall back to original 40 | * max1() logic. 41 | */ 42 | int cond2 = sign(a) * cond1 + sign(a - b) * flip(cond1); 43 | return a * cond2 + b * flip(cond2); 44 | } 45 | 46 | //TEST---------------------------------- 47 | public static void main(String[] args) { 48 | println(max1(-1, 5) + " " + max2(-1, 5)); 49 | println(max1(-1, -5) + " " + max2(-1, -5)); 50 | println(max1(Integer.MAX_VALUE, Integer.MIN_VALUE) + " " + max2(Integer.MAX_VALUE, Integer.MIN_VALUE)); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/chap17/Q04_2.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write a method which finds the negation of a number. 7 | * Write a method which finds the absolute value of a number. 8 | * You should not use if-else or any other comparison operator. 9 | */ 10 | public class Q04_2 { 11 | public static int abs(int n) { 12 | int cond = sign(n); 13 | return n * cond + negate(n) * flip(cond); 14 | } 15 | 16 | public static int negate(int n) { 17 | return (~n) + 1; 18 | } 19 | 20 | public static int sign(int n) { 21 | return flip((n >> 31) & 1); 22 | } 23 | 24 | public static int flip(int i) { 25 | return 1 ^ i; 26 | } 27 | 28 | //TEST---------------------------------- 29 | public static void main(String[] args) { 30 | println(abs(0)); 31 | println(abs(-1121)); 32 | println(abs(Integer.MAX_VALUE)); 33 | println(abs(Integer.MIN_VALUE + 1)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/chap17/Q05.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * The Game of Master Mind is played as follows: 9 | * The computer has four slots, and each slot will contain a ball 10 | * that is red (R), yellow (Y), green (C) or blue (B). For example, 11 | * the computer might have RGGB (Slot # 1 is red, Slots #2 and #3 12 | * are green, Slot #4 is blue). 13 | * 14 | * You, the user, are trying to guess the solution. You might, for 15 | * example, guess YRGB. When you guess the correct color for the 16 | * correct slot, you get a "hit". If you guess a color that exists 17 | * but is in the wrong slot, you get a "pseudo-hit". Note that a 18 | * slot that is a hit can never count as a pseudo-hit. 19 | * 20 | * For example, if the actual solution is RGBY and you guess GGRR, 21 | * you have one hit and one pseudo-hit. 22 | * 23 | * Write a method that, given a guess and a solution, returns the 24 | * number of hits and pseudo-hits. 25 | */ 26 | public class Q05 { 27 | public static int[] playMasterMind(String solution, String guess) { 28 | if (solution == null || guess == null) return null; 29 | if (solution.length() != guess.length()) return new int[] {0, 0}; 30 | 31 | int hits = 0, pseudoHits = 0; 32 | HashMap map = new HashMap(); 33 | for (int i = 0; i < solution.length(); ++i) { 34 | char letter = solution.charAt(i); 35 | if (letter == guess.charAt(i)) { 36 | ++hits; 37 | } else { 38 | Integer cnt = map.get(letter); 39 | if (cnt == null) { 40 | map.put(letter, 1); 41 | } else { 42 | map.put(letter, ++cnt); 43 | } 44 | } 45 | } 46 | for (int i = 0; i < guess.length(); ++i) { 47 | char letter = guess.charAt(i); 48 | if (letter != solution.charAt(i) && map.containsKey(letter)) { 49 | Integer cnt = map.get(letter); 50 | if (cnt > 0) { 51 | map.put(letter, --cnt); 52 | ++pseudoHits; 53 | } 54 | } 55 | } 56 | return new int[] {hits, pseudoHits}; 57 | } 58 | 59 | //TEST---------------------------------- 60 | public static void main(String[] args) { 61 | test("RGBY", "GRRR"); 62 | test("RGBY", "GGRR"); 63 | test("RGBVEWIDMRENI4WQTYHUKYHUKY", "GGDF6Q7G8EFWJIOKRJHBTVHUKY"); 64 | } 65 | 66 | private static void test(String solution, String guess) { 67 | int[] result = playMasterMind(solution, guess); 68 | println(result[0] + " " + result[1]); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/chap17/Q06.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given an array of integers, write a method to find indices m 7 | * and n such that if you sorted elements m through n, the entire 8 | * array would be sorted. Minimize n - m. 9 | * 10 | * EXAMPLE 11 | * Input: 1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19 12 | * Output: (3, 9) 13 | */ 14 | public class Q06 { 15 | /* 16 | * If sorted, this relation should hold: 17 | * last(left_part) <= min(middle_part) 18 | * first(right_part) >= max(middle_part) 19 | */ 20 | public static int[] findUnsortedPart(int[] a) { 21 | if (a == null) return null; 22 | int left = 0; 23 | while (left <= a.length - 2 && a[left] <= a[left + 1]) ++left; 24 | int right = a.length - 1; 25 | while (right >= 1 && a[right] >= a[right - 1]) --right; 26 | if (left >= right) return new int[] {-1, -1}; 27 | int midMin = Integer.MAX_VALUE, midMax = Integer.MIN_VALUE; 28 | for (int i = left; i <= right; ++i) { 29 | if (a[i] > midMax) midMax = a[i]; 30 | if (a[i] < midMin) midMin = a[i]; 31 | } 32 | while (left >= 0 && a[left] > midMin) --left; 33 | while (right <= a.length - 1 && a[right] < midMax) ++right; 34 | return new int[] {left + 1, right - 1}; 35 | } 36 | 37 | //TEST---------------------------------- 38 | public static void main(String[] args) { 39 | test(new int[] {-1, -2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19}); 40 | test(new int[] {-1, -2, 4, 7, 7, 10, 11, 7, 12, 12, 12, 16, 18, 19}); 41 | test(new int[] {1, 7, 7, 7, 12, 12, 12, 16}); 42 | test(new int[] {6, 5, 4, 3, -2, -1}); 43 | } 44 | 45 | private static void test(int[] a) { 46 | int[] result = findUnsortedPart(a); 47 | println(result[0] + " " + result[1]); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/chap17/Q07.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Given any integer, print an English phrase that describes 7 | * the integer (e.g., "One Thousand, Two Hundred Thirty Four"). 8 | */ 9 | public class Q07 { 10 | private static String[] digits = {"One", "Two", "Three","Four", "Five", "Six", "Seven", "Eight", "Nine"}; 11 | private static String[] teens = {"Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"}; 12 | private static String[] tens = {"Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"}; 13 | private static String[] bigs = {"", "Thousand", "Million", "Billion"}; 14 | 15 | public static String intToString(int n) { 16 | if (n == 0) return "Zero"; 17 | if (n < 0) return "Negative " + intToString(-n); 18 | String ret = ""; 19 | int i = 0; 20 | while (n > 0) { 21 | String hundredSegment = convertHundred(n % 1000); 22 | if (!hundredSegment.isEmpty()) { 23 | ret = hundredSegment + bigs[i] + " " + ret; 24 | } 25 | n /= 1000; 26 | ++i; 27 | } 28 | return ret.trim(); 29 | } 30 | 31 | private static String convertHundred(int n) { 32 | String ret = ""; 33 | if (n >= 100) { 34 | ret += digits[n / 100 - 1] + " Hundred "; 35 | n %= 100; 36 | } 37 | if (n >= 20) { 38 | ret += tens[n / 10 - 2] + " "; 39 | n %= 10; 40 | } 41 | if (n >= 10) { 42 | ret += teens[n % 10] + " "; 43 | n = 0; 44 | } 45 | if (n > 0) { 46 | ret += digits[n - 1] + " "; 47 | } 48 | return ret; 49 | } 50 | 51 | //TEST---------------------------------- 52 | public static void main(String[] args) { 53 | println(intToString(21)); 54 | println(intToString(121)); 55 | println(intToString(789702501)); 56 | println(intToString(-1000000)); 57 | println(intToString(-1000000200)); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/chap17/Q08.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * You are given an array of integers (both positive and negative). 7 | * Find the contiguous sequence with the largest sum. Return the sum. 8 | * 9 | * EXAMPLE 10 | * Input: [2, -8, 3, -2, 4, -10] 11 | * Outputs: [3, -2, 4] 12 | */ 13 | public class Q08 { 14 | // returns [startIndex, endIndex, maxSum] 15 | public static int[] getMaxSumSequence(int[] a) { 16 | if (a == null || a.length == 0) return null; 17 | 18 | int start = 0, end = 0, sum = 0; 19 | int[] ret = {0, 0, Integer.MIN_VALUE}; 20 | for (int i = 0; i < a.length; ++i) { 21 | sum += a[i]; 22 | end = i; 23 | if (sum > ret[2]) { 24 | ret[0] = start; 25 | ret[1] = end; 26 | ret[2] = sum; 27 | } 28 | if (sum < 0) { 29 | sum = 0; 30 | start = i + 1; 31 | } 32 | } 33 | return ret; 34 | } 35 | 36 | //TEST---------------------------------- 37 | public static void main(String[] args) { 38 | test(new int[] {2, -10}); 39 | test(new int[] {2, -10, 50}); 40 | test(new int[] {2, -8, 3, 5, 1, -2, 4, -10}); 41 | test(new int[] {-8, -2, -10}); 42 | } 43 | 44 | private static void test(int[] a) { 45 | int[] ret = getMaxSumSequence(a); 46 | println(ret[0] + " " + ret[1] + " " + ret[2]); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/chap17/Q09.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * Design a method to find the frequency of occurrences of any 9 | * given word in a book. 10 | */ 11 | public class Q09 { 12 | private static HashMap map = new HashMap(); 13 | 14 | // assume words are case-insensitive 15 | public static HashMap buildFrequencyMap(String book) { 16 | if (book == null) return null; 17 | String[] words = book.split("\\s+"); 18 | 19 | for (String word : words) { 20 | if (word == null) continue; 21 | word = word.toLowerCase(); 22 | map.put(word, map.getOrDefault(word, 0) + 1); 23 | } 24 | return map; 25 | } 26 | 27 | public static int getFrequency(String word) { 28 | if (word == null || word.trim().isEmpty()) return -1; 29 | return map.getOrDefault(word.toLowerCase(), 0); 30 | } 31 | 32 | //TEST---------------------------------- 33 | public static void main(String[] args) { 34 | String book = "Java String array FAQ: Can you share some Java array examples," + 35 | " specifically some String array examples, as well as the Java 5 for loop syntax?"; 36 | buildFrequencyMap(book); 37 | println(getFrequency(" ")); 38 | println(getFrequency("python")); 39 | println(getFrequency("java")); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/chap17/Q10.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Since XML is very verbose, you are given a way of encoding it 7 | * where each tag gets mapped to a pre-defined integer value. The 8 | * language/grammar is as follows: 9 | * Element --> Tag Attributes END Children END 10 | * Attribute --> Tag Value 11 | * END --> 0 12 | * Tag --> some predefined mapping to int 13 | * Value --> string value END 14 | * 15 | * For example, the following XML might be converted into the 16 | * compressed string below (assuming a mapping of family -> 1, 17 | * person -> 2, firstName -> 3, lastName -> 4, state -> 5). 18 | * 19 | * Some Message 20 | * 21 | * Becomes: 22 | * 1 4 McDowell 5 CA 0 2 3 Gayle 0 Some Message 0 0 23 | * Write code to print the encoded version of an XML element 24 | * (passed in Element and Attribute objects). 25 | */ 26 | public class Q10 { 27 | public static String encode(Element root) { 28 | StringBuilder sb = new StringBuilder(); 29 | encode(root, sb); 30 | return sb.toString(); 31 | } 32 | private static void encode(Element root, StringBuilder sb) { 33 | if (root == null) return; 34 | encode(root.getTag(), sb); 35 | for (Attribute a : root.getAttributes()) { 36 | encode(a, sb); 37 | } 38 | end(sb); 39 | if (root.hasValue()) { 40 | encode(root.getValue(), sb); 41 | } 42 | for (Element e : root.getChildren()) { 43 | encode(e, sb); 44 | } 45 | end(sb); 46 | } 47 | 48 | private static void encode(Attribute a, StringBuilder sb) { 49 | if (a == null) return; 50 | encode(a.getTag(), sb); 51 | encode(a.getValue(), sb); 52 | } 53 | 54 | private static void encode(String s, StringBuilder sb) { 55 | sb.append(s).append(" "); 56 | } 57 | 58 | private static void end(StringBuilder sb) { 59 | encode("0", sb); 60 | } 61 | 62 | class Element { 63 | /* Not implemented */ 64 | String getTag() { return null; } 65 | List getAttributes() { return null; } 66 | List getChildren() { return null; } 67 | boolean hasValue() { return false; } 68 | String getValue() { return null; } 69 | } 70 | 71 | class Attribute { 72 | /* Not implemented */ 73 | String getTag() { return null; } 74 | String getValue() { return null; } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/chap17/Q11.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Random; 6 | 7 | /** 8 | * Implement a method rand7() given rand5() That is, given a method 9 | * that generates a random number between 0 and 4 (inclusive), write 10 | * a method that generates a random number between 0 and 6 (inclusive). 11 | */ 12 | public class Q11 { 13 | private static Random r = new Random(); 14 | 15 | public static int rand7() { 16 | while(true) { 17 | int n = 5 * rand5() + rand5(); 18 | if (n < 21) return n % 7; 19 | } 20 | } 21 | 22 | public static int rand5() { 23 | return r.nextInt(5); 24 | } 25 | 26 | //TEST---------------------------------- 27 | public static void main(String[] args) { 28 | final int N = 10; 29 | for (int i = 0; i < N; ++i) 30 | print(rand7() + " "); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/chap17/Q12.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.HashMap; 8 | 9 | /** 10 | * Design an algorithm to find all pairs of integers within an 11 | * array which sum to a specified value. 12 | * 13 | * The array only contains unique values. 14 | */ 15 | public class Q12 { 16 | // O(n) time, O(n) space 17 | public static ArrayList> twoSum(int[] a, int sum) { 18 | if (a == null) return null; 19 | ArrayList> result = new ArrayList>(); 20 | HashMap map = new HashMap(); 21 | 22 | for (int i = 0; i < a.length; ++i) { 23 | int comp = sum - a[i]; 24 | if (map.containsKey(comp)) { 25 | ArrayList pair = new ArrayList(); 26 | pair.add(a[map.get(comp)]); 27 | pair.add(a[i]); 28 | result.add(pair); 29 | } 30 | map.put(a[i], i); 31 | } 32 | return result; 33 | } 34 | 35 | // O(n log n) time, O(log n) space for sorting 36 | public static ArrayList> twoSum2(int[] a, int sum) { 37 | if (a == null) return null; 38 | Arrays.sort(a); 39 | ArrayList> result = new ArrayList>(); 40 | 41 | int left = 0, right = a.length - 1; 42 | while (left < right) { 43 | if (a[left] + a[right] == sum) { 44 | ArrayList pair = new ArrayList(); 45 | pair.add(a[left]); 46 | pair.add(a[right]); 47 | result.add(pair); 48 | ++left; 49 | --right; 50 | } else if (a[left] + a[right] < sum) { 51 | ++left; 52 | } else { 53 | --right; 54 | } 55 | } 56 | return result; 57 | } 58 | 59 | //TEST---------------------------------- 60 | public static void main(String[] args) { 61 | println(twoSum(new int[] {2, 5, 1, -1, 10, 7, 17, -3, -5}, 12)); 62 | println(twoSum2(new int[] {2, 5, 1, -1, 10, 7, 17, -3, -5}, 12)); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/chap17/Q12_2.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | 8 | /** 9 | * Design an algorithm to find all pairs of integers within 10 | * an array which sum to a specified value. 11 | * 12 | * The array might contain duplicates. 13 | * Return a list of ALL possible index pairs. 14 | */ 15 | public class Q12_2 { 16 | // average O(n) time, O(n) space 17 | public static ArrayList> twoSum(int[] a, int sum) { 18 | if (a == null) return null; 19 | ArrayList> result = new ArrayList>(); 20 | HashMap> map = new HashMap>(); 21 | 22 | for (int i = 0; i < a.length; ++i) { 23 | int comp = sum - a[i]; 24 | if (map.containsKey(comp)) { 25 | for (int compIndex : map.get(comp)) { 26 | ArrayList pair = new ArrayList(); 27 | pair.add(compIndex); 28 | pair.add(i); 29 | result.add(pair); 30 | } 31 | } 32 | ArrayList compIndexList = new ArrayList(); 33 | if (map.containsKey(a[i])) compIndexList = map.get(a[i]); 34 | compIndexList.add(i); 35 | map.put(a[i], compIndexList); 36 | } 37 | return result; 38 | } 39 | 40 | //TEST---------------------------------- 41 | public static void main(String[] args) { 42 | println(twoSum(new int[] {2, 5, 1, -1, 10, 7, 5, 7, 10, 17, -3, -5}, 12)); 43 | println(twoSum(new int[] {1, 1, 1, 1, 1, 1}, 2)); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/chap17/Q13.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Consider a simple node-like data structure called BiNode, 7 | * which has pointers to two other nodes. The data structure 8 | * BiNode could be used to represent both a binary tree (where 9 | * node1 is the left node and node2 is the right node) or a 10 | * doubly linked list (where node1 is the previous node and 11 | * node2 is the next node). Implement a method to convert a 12 | * binary search tree (implemented with BiNode) into a doubly 13 | * linked list. The values should be kept in order and the 14 | * operation should be performed in place (that is, on the 15 | * original data structure). 16 | */ 17 | public class Q13 { 18 | public static void inorderTraverse(BiNode n) { 19 | if (n == null) return; 20 | inorderTraverse(n.node1); 21 | addNode(n); 22 | inorderTraverse(n.node2); 23 | } 24 | 25 | private static void addNode(BiNode n) { 26 | if (head == null) { 27 | head = tail = n; 28 | head.node1 = head.node2 = null; 29 | } else { 30 | tail.node2 = n; 31 | n.node1 = tail; 32 | tail = n; 33 | } 34 | } 35 | 36 | private static BiNode head = null, tail = null; 37 | 38 | private static class BiNode { 39 | BiNode node1, node2; 40 | int value; 41 | public BiNode(int v, BiNode n1, BiNode n2) { 42 | value = v; 43 | node1 = n1; 44 | node2 = n2; 45 | } 46 | public BiNode(int v) { 47 | this(v, null, null); 48 | } 49 | } 50 | 51 | //TEST---------------------------------- 52 | public static void main(String[] args) { 53 | final int N = 7; 54 | BiNode[] ns = new BiNode[N + 1]; 55 | for (int i = 1; i < ns.length; ++i) { 56 | ns[i] = new BiNode(i); 57 | } 58 | /* 59 | * 7 60 | * / \ 61 | * 3 2 62 | * / / \ 63 | * 1 4 5 64 | * \ 65 | * 6 66 | */ 67 | BiNode root = ns[7]; 68 | ns[7].node1 = ns[3]; 69 | ns[3].node1 = ns[1]; 70 | ns[7].node2 = ns[2]; 71 | ns[2].node1 = ns[4]; 72 | ns[2].node2 = ns[5]; 73 | ns[4].node2 = ns[6]; 74 | 75 | inorderTraverse(root); 76 | printListFromHead(); 77 | printListFromTail(); 78 | } 79 | 80 | private static void printListFromHead() { 81 | printList(head, false); 82 | } 83 | 84 | private static void printListFromTail() { 85 | printList(tail, true); 86 | } 87 | 88 | private static void printList(BiNode n, boolean reversed) { 89 | while (n != null) { 90 | print(n.value); 91 | n = reversed ? n.node1 : n.node2; 92 | if (n != null) print("->"); 93 | } 94 | println(); 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/chap17/Q14.java: -------------------------------------------------------------------------------- 1 | package chap17; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Arrays; 6 | import java.util.HashSet; 7 | 8 | /** 9 | * Oh, no! You have just completed a lengthy document when you have 10 | * an unfortunate Find/Replace mishap. You have accidentally removed 11 | * all spaces, punctuation, and capitalization in the document. A 12 | * sentence like "I reset the computer. It still didn't boot!" would 13 | * become "iresetthecomputeritstilldidntboot". You figure that you 14 | * can add back in the punctuation and capitalization later, once you 15 | * get the individual words properly separated. Most of the words will 16 | * be in a dictionary but some strings, like proper names, will not. 17 | * 18 | * Given a dictionary (a list of words), design an algorithm to find 19 | * the optimal way of "unconcatenating" a sequence of words. In this 20 | * case, "optimal" is defined to be the parsing which minimizes the 21 | * number of unrecognized sequences of characters. 22 | * 23 | * For example, the string "jesslookedjustliketimherbrother" would be 24 | * optimally parsed as "JESS looked just like TIM her brother". This 25 | * parsing has seven unrecognized characters, which we have capitalized 26 | * for clarity. 27 | */ 28 | public class Q14 { 29 | public static int parse(String sentence, HashSet dictionary) { 30 | if (sentence == null || sentence.isEmpty()) return 0; 31 | int len = sentence.length(); 32 | if (dictionary == null || dictionary.isEmpty()) return len; 33 | int[] dp = new int[len + 1]; 34 | Arrays.fill(dp, Integer.MAX_VALUE); 35 | dp[0] = 0; 36 | for (int i = 1; i <= len; ++i) { 37 | for (int j = 0; j < i; ++j) { 38 | String word = sentence.substring(j, i); 39 | int unrecogCharNum = dictionary.contains(word) ? 0 : word.length(); 40 | int totalUnrecogCharNum = dp[j] + unrecogCharNum; 41 | if (totalUnrecogCharNum < dp[i]) dp[i] = totalUnrecogCharNum; 42 | // recurrence: 43 | // dp[i] = min(dp[i], dp[j] + unrecogCharNum) 44 | // where dp[n] is minimal number of unrecognized chars in first n chars 45 | } 46 | } 47 | return dp[len]; 48 | } 49 | 50 | //TEST---------------------------------- 51 | public static void main(String[] args) { 52 | String[] strings = { 53 | "looked", "just", "like", "her", "brother" 54 | }; 55 | HashSet dictionary = new HashSet(Arrays.asList(strings)); 56 | String sentence = "jesslookedjustliketimherbrother"; 57 | println(parse(sentence, dictionary)); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/chap18/Q01.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write a function that adds two numbers. You should not use + 7 | * or any arithmetic operators. 8 | * 9 | * FOLLOW UP 10 | * Similarly, implement subtraction. 11 | */ 12 | public class Q01 { 13 | /* 14 | * SOLUTION: 15 | * e.g. 759 + 674 16 | * 1. Add 759 + 674, but "forget" to carry. I then get 323. 17 | * 2. Add 759 + 674 but only do the carrying, rather than the 18 | * addition of each digit. I then get 1110. 19 | * 3. Add the result of the first two operations (recursively, 20 | * using the same process described in step 1 and 2): 21 | * 1110 + 323 = 1433. 22 | * 23 | * Now, how would we do this in binary? 24 | * 1. If I add two binary numbers together, but forget to carry, 25 | * the ith bit in the sum will be 0 only if a and b have the same 26 | * ith bit (both 0 or both 1). This is essentially an XOR. 27 | * 2. If I add two numbers together but only carry, I will have a 28 | * 1 in the ith bit of the sum only if bits i - 1 of a and b are 29 | * both 1s. This is an AND, shifted. 30 | * 3. Now, recurse until there's nothing to carry. 31 | */ 32 | public static int add(int a, int b) { 33 | if (b == 0) return a; 34 | int sum = a ^ b; // add without carrying 35 | int carry = (a & b) << 1; // add but only do carrying 36 | return add(sum, carry); 37 | } 38 | 39 | public static int negate(int a) { 40 | return add(~a, 1); 41 | } 42 | 43 | public static int subtract(int a, int b) { 44 | return add(a, negate(b)); 45 | } 46 | 47 | //TEST---------------------------------- 48 | public static void main(String[] args) { 49 | test(245, 769); 50 | test(245, -769); 51 | } 52 | 53 | private static void test(int a, int b) { 54 | printfln("%d + %d = %d", a, b, add(a, b)); 55 | printfln("%d - %d = %d", a, b, subtract(a, b)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/chap18/Q02.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Random; 6 | 7 | /** 8 | * Write a method to shuffle a deck of cards. It must be a perfect 9 | * shuffle -- in other words, each of the 52! permutations of the 10 | * deck has to be equally likely. Assume that you are given a random 11 | * number generator which is perfect. 12 | */ 13 | public class Q02 { 14 | /* 15 | * SOLUTION 16 | * Move through the array and, for each element i, swap array[i] 17 | * with a random element between 0 and i, inclusive. 18 | */ 19 | public static void shuffle(int[] a) { 20 | if (a == null) return; 21 | for (int i = 0; i < a.length; ++i) { 22 | int r = rand(0, i); 23 | int tmp = a[i]; 24 | a[i] = a[r]; 25 | a[r] = tmp; 26 | } 27 | } 28 | 29 | private static int rand(int start, int end) { 30 | Random r = new Random(); 31 | return r.nextInt(end - start + 1) + start; 32 | } 33 | 34 | //TEST---------------------------------- 35 | public static void main(String[] args) { 36 | final int N = 5; 37 | int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 38 | for (int i = 0; i < N; ++i) { 39 | shuffle(a); 40 | printArray(a); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/chap18/Q03.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Arrays; 6 | import java.util.Random; 7 | 8 | /** 9 | * Write a method to randomly generates set of m integers from 10 | * an array of size n. Each element must have equal probability 11 | * of being chosen. 12 | */ 13 | public class Q03 { 14 | public static int[] randomize(int[] a, int m) { 15 | if (a == null || m < 0) return null; 16 | if (m >= a.length) m = a.length; 17 | int[] result = Arrays.copyOfRange(a, 0, m); 18 | for (int i = m; i < a.length; ++i) { 19 | int r = rand(0, i); 20 | if (r < m) result[r] = a[i]; 21 | } 22 | return result; 23 | } 24 | 25 | private static int rand(int start, int end) { 26 | Random r = new Random(); 27 | return r.nextInt(end - start + 1) + start; 28 | } 29 | 30 | //TEST---------------------------------- 31 | public static void main(String[] args) { 32 | int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9}; 33 | printArray(randomize(a, 3)); 34 | printArray(randomize(a, 8)); 35 | printArray(randomize(a, 50)); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/chap18/Q04.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | /** 6 | * Write a method to count the number of 2s that appear in all 7 | * the numbers between 0 and n (inclusive). 8 | * 9 | * EXAMPLE 10 | * Input: 25 11 | * Output: 9 (2, 12, 20, 21, 22, 23, 24 and 25. Note that 22 12 | * counts for two 2s.) 13 | */ 14 | public class Q04 { 15 | // Count 2s digit by digit 16 | public static int countTwos(int n) { 17 | if (n < 0) return -1; 18 | int cnt = 0; 19 | int len = String.valueOf(n).length(); 20 | for (int i = 0; i < len; ++i) { 21 | cnt += countTwosAtDigit(n, i); 22 | } 23 | return cnt; 24 | } 25 | 26 | private static int countTwosAtDigit(int n, int d) { 27 | int powerOf10 = (int) Math.pow(10, d); 28 | int nextPowerOf10 = 10 * powerOf10; 29 | int roundDown = n - n % nextPowerOf10; 30 | int roundUp = roundDown + nextPowerOf10; 31 | int digit = (n / powerOf10) % 10; 32 | if (digit < 2) { 33 | return roundDown / 10; 34 | } else if (digit > 2) { 35 | return roundUp / 10; 36 | } else { 37 | return roundDown / 10 + n % powerOf10 + 1; 38 | } 39 | } 40 | 41 | // Brute force 42 | public static int countTwosBF(int n) { 43 | if (n < 0) return -1; 44 | int cnt = 0; 45 | for (int i = 0; i <= n; ++i) { 46 | cnt += countTwosInNumber(i); 47 | } 48 | return cnt; 49 | } 50 | 51 | private static int countTwosInNumber(int n) { 52 | int cnt = 0; 53 | while (n > 0) { 54 | if (n % 10 == 2) ++cnt; 55 | n /= 10; 56 | } 57 | return cnt; 58 | } 59 | 60 | //TEST---------------------------------- 61 | public static void main(String[] args) { 62 | test(22); 63 | test(678487); 64 | } 65 | 66 | private static void test(int n) { 67 | printfln("Count 2s for %d", n); 68 | printfln("countTwos: %d", countTwos(n)); 69 | printfln("countTwosBF: %d", countTwosBF(n)); 70 | println(); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/chap18/Q05.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.HashMap; 6 | import java.util.ArrayList; 7 | 8 | /** 9 | * You have a large text file containing words. Given any two words, 10 | * find the shortest distance (in terms of number of words) between 11 | * them in the file. If the operation will be repeated many times 12 | * for the same file (but different pairs of words), can you 13 | * optimize your solution? 14 | */ 15 | public class Q05 { 16 | public static int findShortextPath(String[] text, String word1, String word2) { 17 | if (text == null || word1 == null || word2 == null || word1.isEmpty() || word2.isEmpty()) return -1; 18 | 19 | int p1 = -1, p2 = -1, minDistance = text.length; 20 | for (int i = 0; i < text.length; ++i) { 21 | if (text[i].equals(word1)) p1 = i; 22 | else if ((text[i].equals(word2))) p2 = i; 23 | if (p1 != -1 && p2 != -1) minDistance = Math.min(minDistance, Math.abs(p1 - p2)); 24 | } 25 | return minDistance; 26 | } 27 | 28 | public static HashMap> preprocess(String[] text) { 29 | HashMap> map = new HashMap>(); 30 | for (int i = 0; i < text.length; ++i) { 31 | String word = text[i]; 32 | ArrayList indexes = map.getOrDefault(word, new ArrayList()); 33 | indexes.add(i); 34 | map.put(word, indexes); 35 | } 36 | return map; 37 | } 38 | 39 | public static int findShortextPath2(String[] text, String word1, String word2) { 40 | if (text == null || word1 == null || word2 == null || word1.isEmpty() || word2.isEmpty()) return -1; 41 | 42 | HashMap> map = preprocess(text); 43 | 44 | int p1 = 0, p2 = 0, minDistance = text.length; 45 | ArrayList list1 = map.get(word1), list2 = map.get(word2); 46 | if (list1 == null || list2 == null) return minDistance; 47 | while (p1 < list1.size() && p2 < list2.size()) { 48 | int index1 = list1.get(p1), index2 = list2.get(p2); 49 | minDistance = Math.min(minDistance, Math.abs(index1 - index2)); 50 | if (index1 < index2) ++p1; 51 | else ++p2; 52 | } 53 | return minDistance; 54 | } 55 | 56 | //TEST---------------------------------- 57 | public static void main(String[] args) { 58 | String book = "Java String array FAQ: Can you share some Java array examples," + 59 | " specifically some String array examples, as well as the Java 5 for loop syntax?"; 60 | String[] text = book.split("\\s+"); 61 | 62 | println(findShortextPath(text, "Java", "as")); 63 | println(findShortextPath(text, "FAQ:", "examples,")); 64 | println(findShortextPath2(text, "Java", "as")); 65 | println(findShortextPath2(text, "FAQ:", "examples,")); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/chap18/Q06.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.PriorityQueue; 8 | 9 | /** 10 | * Describe an algorithm to find the smallest one million numbers in 11 | * one billion numbers. Assume that the computer memory can hold all 12 | * one billion numbers. 13 | * 14 | * SOLUTION 15 | * 1. Sort. O(n log n) time, O(log n) space. 16 | * 2. Heap. O(n log m) time, O(m) space. 17 | * 3. Quick Select. O(n) time, O(log n) space. Need to modify input array. 18 | */ 19 | public class Q06 { 20 | public static ArrayList findNSmallestElements(ArrayList nums, int n) { 21 | if (nums == null || n < 0) return null; 22 | PriorityQueue maxheap = new PriorityQueue(n, Collections.reverseOrder()); 23 | for (int num : nums) { 24 | if (maxheap.size() < n) { 25 | maxheap.offer(num); 26 | } else { 27 | if (num < maxheap.peek()) { 28 | maxheap.poll(); 29 | maxheap.offer(num); 30 | } 31 | } 32 | } 33 | 34 | ArrayList result = new ArrayList(); 35 | while (!maxheap.isEmpty() ) { 36 | result.add(maxheap.poll()); 37 | } 38 | return result; 39 | } 40 | 41 | //TEST---------------------------------- 42 | public static void main(String[] args) { 43 | ArrayList nums = new ArrayList(); 44 | final int N = 1000; 45 | for (int i = 0; i < N; ++i) nums.add(i); 46 | Collections.shuffle(nums); 47 | println(findNSmallestElements(nums, 50)); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/chap18/Q07.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Comparator; 8 | import java.util.HashMap; 9 | 10 | /** 11 | * Given a list of words, write a program to find the longest word 12 | * made of other words in the list. 13 | * Returns all possible occurrences. 14 | * 15 | * EXAMPLE 16 | * Input: "cat", "banana", "dog", "nana", "my", "walk", "walker", 17 | * "baby", "dogwalkers", "s", "babymybaby" 18 | * Output: ["dogwalkers", "babymybaby"] 19 | */ 20 | public class Q07 { 21 | public static ArrayList findLongestWord(String[] words) { 22 | if (words == null) return null; 23 | sortWordsByLength(words); 24 | ArrayList result = new ArrayList(); 25 | HashMap map = new HashMap(); 26 | for (String word : words) { 27 | map.put(word, true); 28 | } 29 | int maxLen = 0; 30 | for (String word : words) { 31 | if (isValidWord(word, true, map) && word.length() >= maxLen) { 32 | result.add(word); 33 | maxLen = word.length(); 34 | } 35 | } 36 | return result; 37 | } 38 | 39 | private static void sortWordsByLength(String[] words) { 40 | Arrays.sort(words, new Comparator() { 41 | @Override 42 | public int compare(String o1, String o2) { 43 | return ((Integer) o2.length()).compareTo(o1.length()); 44 | } 45 | }); 46 | } 47 | 48 | private static boolean isValidWord(String word, boolean isOriginal, HashMap map) { 49 | if (!isOriginal && map.containsKey(word)) { 50 | return map.get(word); 51 | } 52 | for (int i = 1; i < word.length(); ++i) { 53 | String left = word.substring(0, i); 54 | String right = word.substring(i); 55 | if (map.containsKey(left) && 56 | map.get(left) == true && 57 | isValidWord(right, false, map)) { 58 | return true; 59 | } 60 | } 61 | map.put(word, false); 62 | return false; 63 | } 64 | 65 | //TEST---------------------------------- 66 | public static void main(String[] args) { 67 | String[] a = {"cat", "banana", "dog", "nana", "my", "walk", 68 | "walker", "baby", "dogwalkers", "s", "babymybaby"}; 69 | println(findLongestWord(a)); 70 | a = new String[] {"A", "A", "A", "B", "C", "ABC", "AAA", "BAA", "B"}; 71 | println(findLongestWord(a)); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/chap18/Q07_2.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.Comparator; 8 | import java.util.HashMap; 9 | 10 | /** 11 | * Given a list of words, write a program to find the longest word 12 | * made of other words in the list. 13 | * Returns all possible occurrences. 14 | * 15 | * FOLLOW UP 16 | * What if each single word can only be used once to construct 17 | * other words? 18 | * 19 | * EXAMPLE 20 | * Input: "cat", "banana", "dog", "nana", "my", "walk", "walker", 21 | * "baby", "dogwalkers", "s", "babymybaby" 22 | * Output: ["dogwalkers"] 23 | */ 24 | public class Q07_2 { 25 | public static ArrayList findLongestWord(String[] words) { 26 | if (words == null) return null; 27 | sortWordsByLength(words); 28 | ArrayList result = new ArrayList(); 29 | HashMap map = new HashMap(); 30 | for (String word : words) { 31 | int cnt = 0; 32 | if (map.containsKey(word)) cnt = map.get(word); 33 | map.put(word, ++cnt); 34 | } 35 | int maxLen = 0; 36 | for (String word : words) { 37 | if (isValidWord(word, true, map) && word.length() >= maxLen) { 38 | result.add(word); 39 | maxLen = word.length(); 40 | } 41 | } 42 | return result; 43 | } 44 | 45 | private static void sortWordsByLength(String[] words) { 46 | Arrays.sort(words, new Comparator() { 47 | @Override 48 | public int compare(String o1, String o2) { 49 | return ((Integer) o2.length()).compareTo(o1.length()); 50 | } 51 | }); 52 | } 53 | 54 | private static boolean isValidWord(String word, boolean isOriginal, HashMap map) { 55 | if (!isOriginal && map.containsKey(word) && map.get(word) > 0) { 56 | map.put(word, map.get(word) - 1); 57 | return true; 58 | } 59 | for (int i = 1; i < word.length(); ++i) { 60 | String left = word.substring(0, i); 61 | String right = word.substring(i); 62 | if (map.containsKey(left) && map.get(left) > 0) { 63 | map.put(left, map.get(left) - 1); 64 | if (isValidWord(right, false, map)) { 65 | return true; 66 | } 67 | map.put(left, map.get(left) + 1); 68 | } 69 | } 70 | return false; 71 | } 72 | 73 | //TEST---------------------------------- 74 | public static void main(String[] args) { 75 | String[] a = {"cat", "banana", "dog", "nana", "my", "walk", 76 | "walker", "baby", "dogwalkers", "s", "babymybaby"}; 77 | println(findLongestWord(a)); 78 | a = new String[] {"A", "A", "A", "B", "C", "ABC", "AAA", "BAA", "B"}; 79 | println(findLongestWord(a)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/chap18/Q08.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | import static helpers.Trie.*; 5 | 6 | /** 7 | * Given a long string s and an array of smaller strings T, design a 8 | * method to search s for each small string in T. 9 | */ 10 | public class Q08 { 11 | private static TrieNode suffixTreeRoot = new TrieNode(); 12 | 13 | public static void buildSuffixTree(String s) { 14 | for (int i = s.length() - 1; i >= 0; --i) { 15 | addWord(suffixTreeRoot, s.substring(i)); 16 | } 17 | } 18 | 19 | public static void search(String[] T) { 20 | for (String t : T) { 21 | println(getWords(suffixTreeRoot, t)); 22 | } 23 | } 24 | 25 | //TEST---------------------------------- 26 | public static void main(String[] args) { 27 | String s = "theveryverylongbananas"; 28 | String[] T = { 29 | "s", 30 | "a", 31 | "ver", 32 | "verr", 33 | }; 34 | 35 | buildSuffixTree(s); 36 | search(T); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/chap18/Q09.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.Collections; 6 | import java.util.PriorityQueue; 7 | 8 | /** 9 | * Numbers are randomly generated and passed to a method. Write a 10 | * program to find and maintain the median value as new values are 11 | * generated. 12 | * 13 | * SOLUTION 14 | * Use a max heap and a min heap to maintain the stream, where 15 | * maxheap.size() == minheap.size() or 16 | * maxheap.size() - 1 == minheap.size() 17 | * always holds. 18 | */ 19 | public class Q09 { 20 | private static final int N = 100; 21 | // a max heap that contains all SMALL elements 22 | private static PriorityQueue maxHeap = new PriorityQueue(N, Collections.reverseOrder()); 23 | // a min heap that contains all LARGE elements 24 | private static PriorityQueue minHeap = new PriorityQueue(N); 25 | 26 | // O(log n) time, O(n) space 27 | public static void track(int n) { 28 | if (maxHeap.size() == minHeap.size()) { 29 | if (maxHeap.isEmpty() || n < minHeap.peek()) { 30 | maxHeap.offer(n); 31 | } else { 32 | maxHeap.offer(minHeap.poll()); 33 | minHeap.offer(n); 34 | } 35 | } else { 36 | if (n > maxHeap.peek()) { 37 | minHeap.offer(n); 38 | } else { 39 | minHeap.offer(maxHeap.poll()); 40 | maxHeap.offer(n); 41 | } 42 | } 43 | } 44 | 45 | // O(1) time 46 | public static double getMedian() { 47 | if (maxHeap.size() == minHeap.size()) { 48 | return (maxHeap.peek() + minHeap.peek()) / 2.0; 49 | } else { 50 | return maxHeap.peek(); 51 | } 52 | } 53 | 54 | //TEST---------------------------------- 55 | public static void main(String[] args) { 56 | for (int i = 0; i < 5; ++i) { 57 | track(i); 58 | println(getMedian()); 59 | } 60 | for (int i = 100; i < 150; i += 5) { 61 | track(i); 62 | println(getMedian()); 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/chap18/Q10.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Arrays; 7 | import java.util.HashMap; 8 | import java.util.HashSet; 9 | import java.util.LinkedList; 10 | 11 | /** 12 | * Given two words of equal length that are in a dictionary, write a 13 | * method to transform one word into another word by changing only 14 | * one letter at a time. The new word you get in each step must be 15 | * in the dictionary. 16 | * 17 | * EXAMPLE 18 | * Input: DAMP, LIKE 19 | * Output: DAMP -> LAMP -> LIMP -> LIME -> LIKE 20 | */ 21 | public class Q10 { 22 | // BFS with a backtrack map 23 | public static ArrayList transform(String start, String end, HashSet dictionary) { 24 | LinkedList queue = new LinkedList(); 25 | HashMap backtrackMap = new HashMap(); 26 | HashSet visited = new HashSet(); 27 | ArrayList result = new ArrayList(); 28 | queue.add(start); 29 | visited.add(start); 30 | while(!queue.isEmpty()) { 31 | String word = queue.remove(); 32 | for (String newWord : transformOneLetter(word, dictionary)) { 33 | if (!visited.contains(newWord)) { 34 | visited.add(newWord); 35 | backtrackMap.put(newWord, word); 36 | if (newWord.equals(end)) { 37 | backtrack(start, newWord, backtrackMap, result); 38 | break; 39 | } 40 | queue.add(newWord); 41 | } 42 | } 43 | } 44 | return result; 45 | } 46 | 47 | private static HashSet transformOneLetter(String word, HashSet dictionary) { 48 | HashSet result = new HashSet(); 49 | for (int i = 0; i < word.length(); ++i) { 50 | StringBuilder sb = new StringBuilder(word); 51 | for (char letter = 'a'; letter <= 'z'; ++letter) { 52 | if (sb.charAt(i) != letter) { 53 | sb.setCharAt(i, letter); 54 | String newWord = sb.toString(); 55 | if (dictionary.contains(newWord)) { 56 | result.add(newWord); 57 | } 58 | } 59 | } 60 | } 61 | return result; 62 | } 63 | 64 | private static void backtrack(String start, String word, HashMap backtrackMap, ArrayList result) { 65 | result.add(word); 66 | while (backtrackMap.containsKey(word)) { 67 | if (word.equals(start)) break; 68 | word = backtrackMap.get(word); 69 | result.add(0, word); 70 | } 71 | } 72 | 73 | //TEST---------------------------------- 74 | public static void main(String[] args) { 75 | String[] words = { 76 | "damp", "lamp", "limp", "lime","line", "like", "wike" 77 | }; 78 | HashSet dictionary = new HashSet(Arrays.asList(words)); 79 | println(transform("damp", "like", dictionary)); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/chap18/Q11.java: -------------------------------------------------------------------------------- 1 | package chap18; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * Imagine you have a square matrix, where each cell (pixel) is either 9 | * black or white. Design an algorithm to find the maximum subsquare(s) 10 | * such that all four borders are filled with black pixels. 11 | * (Suppose black is 1, white is 0 in the matrix.) 12 | */ 13 | public class Q11 { 14 | // Brute force: O(n^4) time, O(1) space, n is the length of side of matrix. 15 | public static ArrayList findLargestSubsquare(int[][] matrix) { 16 | if (matrix == null) return null; 17 | ArrayList result = new ArrayList(); 18 | for (int size = matrix.length; size >= 1; --size) { 19 | for (int i = 0; i < matrix.length - size + 1; ++i) { 20 | for (int j = 0; j < matrix[0].length - size + 1; ++j) { 21 | if (isValid(matrix, i, j, size)) { 22 | result.add(new Square(i, j, size)); 23 | } 24 | } 25 | } 26 | if (!result.isEmpty()) break; 27 | } 28 | return result; 29 | } 30 | 31 | private static boolean isValid(int[][] matrix, int row, int col, int size) { 32 | for (int i = row; i < row + size; ++i) { 33 | if (matrix[i][col] == 0) return false; 34 | if (matrix[i][col + size - 1] == 0) return false; 35 | } 36 | for (int j = col; j < col + size; ++j) { 37 | if(matrix[row][j] == 0) return false; 38 | if(matrix[row + size - 1][j] == 0) return false; 39 | } 40 | return true; 41 | } 42 | 43 | // Preprocess matrix: O(n^3) time, O(n^2) space, n is the length of side of matrix. 44 | public static ArrayList findLargestSubsquare2(int[][] matrix) { 45 | if (matrix == null) return null; 46 | Cell[][] cells = preprocess(matrix); 47 | ArrayList result = new ArrayList(); 48 | for (int size = cells.length; size >= 1; --size) { 49 | for (int i = 0; i < cells.length - size + 1; ++i) { 50 | for (int j = 0; j < cells[0].length - size + 1; ++j) { 51 | if (isValid(cells, i, j, size)) { 52 | result.add(new Square(i, j, size)); 53 | } 54 | } 55 | } 56 | if (!result.isEmpty()) break; 57 | } 58 | return result; 59 | } 60 | 61 | public static Cell[][] preprocess(int[][] matrix) { 62 | int size = matrix.length; 63 | Cell[][] cells = new Cell[size][size]; 64 | 65 | for (int i = size - 1; i >= 0; --i) { 66 | for (int j = size - 1; j >= 0; --j) { 67 | int right = matrix[i][j] + (j == size - 1 ? 0 : cells[i][j + 1].availableRight); 68 | int below = matrix[i][j] + (i == size - 1 ? 0 : cells[i + 1][j].availableBelow); 69 | cells[i][j] = new Cell(below, right); 70 | } 71 | } 72 | return cells; 73 | } 74 | 75 | private static boolean isValid(Cell[][] matrix, int row, int col, int size) { 76 | Cell topLeft = matrix[row][col]; 77 | Cell topRight = matrix[row][col + size - 1]; 78 | Cell bottomLeft = matrix[row + size - 1][col]; 79 | Cell bottomRight = matrix[row + size - 1][col + size - 1]; 80 | return (topLeft.availableBelow - bottomLeft.availableBelow + 1 == size) && 81 | (topRight.availableBelow - bottomRight.availableBelow + 1 == size) && 82 | (topLeft.availableRight - topRight.availableRight + 1 == size) && 83 | (bottomLeft.availableRight - bottomRight.availableRight + 1 == size); 84 | } 85 | 86 | private static class Square { 87 | int row, col, size; 88 | public Square(int r, int c, int s) { 89 | row = r; 90 | col = c; 91 | size = s; 92 | } 93 | public String toString() { 94 | return "(" + row + "," + col + "," + size + ")"; 95 | } 96 | } 97 | 98 | private static class Cell { 99 | int availableBelow, availableRight; 100 | public Cell(int b, int r) { 101 | availableBelow = b; 102 | availableRight = r; 103 | } 104 | } 105 | 106 | //TEST---------------------------------- 107 | public static void main(String[] args) { 108 | int[][] matrix = {{1,0,1,1,1}, 109 | {1,1,1,0,1}, 110 | {1,1,1,1,1}, 111 | {1,1,1,1,0}, 112 | {1,0,1,0,1}}; 113 | println(findLargestSubsquare(matrix)); 114 | println(findLargestSubsquare2(matrix)); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/helpers/Bit.java: -------------------------------------------------------------------------------- 1 | package helpers; 2 | 3 | public class Bit { 4 | public static String toBitString(int n) { 5 | StringBuilder sb = new StringBuilder(); 6 | while (n > 0) { 7 | sb.insert(0, n % 2); 8 | n /= 2; 9 | } 10 | return sb.toString(); 11 | } 12 | 13 | public static int toInt(String bitString) { 14 | int n = 0, base = 1; 15 | char[] bits = bitString.toCharArray(); 16 | for (int i = bits.length - 1; i >=0; --i) { 17 | int bitChar = bits[i]; 18 | if (bitChar != '0' && bitChar != '1') 19 | throw new IllegalArgumentException("Invalid bit string!"); 20 | n += (bitChar - 48) * base; 21 | base *= 2; 22 | } 23 | return n; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/helpers/GraphNode.java: -------------------------------------------------------------------------------- 1 | package helpers; 2 | 3 | import java.util.ArrayList; 4 | 5 | public class GraphNode { 6 | public int value; 7 | public boolean isVisited; 8 | public ArrayList adjacent; 9 | 10 | public GraphNode(int x) { 11 | value = x; 12 | isVisited = false; 13 | adjacent = new ArrayList(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/helpers/LinkedListNode.java: -------------------------------------------------------------------------------- 1 | package helpers; 2 | 3 | import static helpers.Printer.*; 4 | 5 | public class LinkedListNode { 6 | public int data; 7 | public LinkedListNode next; 8 | private static int MAX_PRINT_LENGTH = 500; 9 | 10 | public LinkedListNode(int x) { 11 | data = x; 12 | next = null; 13 | } 14 | 15 | public static LinkedListNode buildList(int[] a) { 16 | if (a == null || a.length == 0) return null; 17 | LinkedListNode n = new LinkedListNode(a[0]); 18 | LinkedListNode head = n; 19 | for (int i = 1; i < a.length; ++i) { 20 | n.next = new LinkedListNode(a[i]); 21 | n = n.next; 22 | } 23 | return head; 24 | } 25 | 26 | public static void printList(LinkedListNode n) { 27 | int i = 0; 28 | while (n != null) { 29 | print(n.data + "->"); 30 | n = n.next; 31 | if (++i > MAX_PRINT_LENGTH) { 32 | println("[MAX_LEN]"); 33 | return; 34 | } 35 | } 36 | println("NULL"); 37 | } 38 | 39 | public String toString() { 40 | return String.valueOf(data); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/helpers/Printer.java: -------------------------------------------------------------------------------- 1 | package helpers; 2 | 3 | public class Printer { 4 | public static void print(Object o) { 5 | System.out.print(o); 6 | } 7 | 8 | public static void println() { 9 | print(lineSeparator()); 10 | } 11 | 12 | public static void println(Object o) { 13 | print(o); 14 | println(); 15 | } 16 | 17 | public static void printf(String s, Object... args) { 18 | print(String.format(s, args)); 19 | } 20 | 21 | public static void printfln(String s, Object... args) { 22 | println(String.format(s, args)); 23 | } 24 | 25 | public static void printArray(int[] a) { 26 | if (a == null) { 27 | print(null); 28 | } else { 29 | for(int n : a) print(n + " "); 30 | } 31 | println(); 32 | } 33 | 34 | public static void printArray(char[] a) { 35 | if (a == null) { 36 | print(null); 37 | } else { 38 | for(char n : a) print(n + " "); 39 | } 40 | println(); 41 | } 42 | 43 | public static void printArray(String[] a) { 44 | if (a == null) { 45 | print(null); 46 | } else { 47 | for(String n : a) print(n + " "); 48 | } 49 | println(); 50 | } 51 | 52 | public static void printArray(int[][] a) { 53 | for (int[] row : a) { 54 | for (int col : row) { 55 | print(col + " "); 56 | } 57 | println(); 58 | } 59 | } 60 | 61 | private static String lineSeparator() { 62 | return System.lineSeparator(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/helpers/TreeNode.java: -------------------------------------------------------------------------------- 1 | package helpers; 2 | 3 | import static helpers.Printer.*; 4 | 5 | public class TreeNode { 6 | public int value; 7 | public TreeNode left; 8 | public TreeNode right; 9 | public TreeNode parent; /* only used for certain cases */ 10 | 11 | public TreeNode(int x) { 12 | value = x; 13 | } 14 | 15 | public String toString() { 16 | return String.valueOf(value); 17 | } 18 | 19 | public static void printTree(TreeNode n) { 20 | if (n == null) return; 21 | println(n.value); 22 | printTree(n.left, 0, true); 23 | printTree(n.right, 0, false); 24 | } 25 | 26 | private static void printTree(TreeNode n, int level, boolean isLeft) { 27 | if (n == null) return; 28 | for (int i = 0; i < level; ++i) print(" "); 29 | if (isLeft) 30 | println("/- " + n.value); 31 | else 32 | println("\\- " + n.value); 33 | printTree(n.left, level + 1, true); 34 | printTree(n.right, level + 1, false); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/helpers/Trie.java: -------------------------------------------------------------------------------- 1 | package helpers; 2 | 3 | import static helpers.Printer.*; 4 | 5 | import java.util.ArrayList; 6 | import java.util.HashMap; 7 | 8 | public class Trie { 9 | public static class TrieNode { 10 | public char character; 11 | public boolean isWord; 12 | public HashMap children; 13 | 14 | public TrieNode(char ch) { 15 | character = ch; 16 | isWord = false; 17 | children = new HashMap(); 18 | } 19 | public TrieNode() { 20 | this('\0'); 21 | } 22 | } 23 | 24 | public static void addWord(TrieNode n, String word) { 25 | if (word == null || word.isEmpty()) return; 26 | char[] characters = word.toCharArray(); 27 | for (char ch: characters) { 28 | if (!n.children.containsKey(ch)) { 29 | n.children.put(ch, new TrieNode(ch)); 30 | } 31 | n = n.children.get(ch); 32 | } 33 | n.isWord = true; 34 | } 35 | 36 | public static ArrayList getAllWords(TrieNode n) { 37 | return getWords(n, ""); 38 | } 39 | 40 | public static boolean hasPrefix(TrieNode n, String prefix) { 41 | return has(n, prefix, false); 42 | } 43 | 44 | public static boolean hasWord(TrieNode n, String prefix) { 45 | return has(n, prefix, true); 46 | } 47 | 48 | private static boolean has(TrieNode n, String prefix, boolean checkHasWord) { 49 | if (prefix == null) return false; 50 | char[] characters = prefix.toCharArray(); 51 | for (char ch: characters) { 52 | if (!n.children.containsKey(ch)) return false; 53 | n = n.children.get(ch); 54 | } 55 | if (checkHasWord) { 56 | return n.isWord; 57 | } else { 58 | return true; 59 | } 60 | } 61 | 62 | public static ArrayList getWords(TrieNode n, String prefix) { 63 | if (prefix == null) return null; 64 | ArrayList result = new ArrayList(); 65 | char[] characters = prefix.toCharArray(); 66 | for (char ch: characters) { 67 | if (!n.children.containsKey(ch)) return result; 68 | n = n.children.get(ch); 69 | } 70 | getWords(n, prefix, result); 71 | return result; 72 | } 73 | 74 | private static void getWords(TrieNode n, String word, ArrayList result) { 75 | if (n.isWord) result.add(word); 76 | for (char ch : n.children.keySet()) { 77 | getWords(n.children.get(ch), word + ch, result); 78 | } 79 | } 80 | 81 | //TEST---------------------------------- 82 | public static void main(String[] args) { 83 | TrieNode root = new TrieNode(); 84 | addWord(root, "dog"); 85 | addWord(root, "dig"); 86 | addWord(root, ""); 87 | addWord(root, null); 88 | addWord(root, "dogman"); 89 | addWord(root, "do"); 90 | addWord(root, "d"); 91 | addWord(root, "apple"); 92 | addWord(root, "application"); 93 | addWord(root, "algorithm"); 94 | printWords(root, "ap"); 95 | printWords(root, "d"); 96 | printWords(root, "none"); 97 | printAllWords(root); 98 | } 99 | 100 | private static void printWords(TrieNode n, String prefix) { 101 | printf("getWords for %s: ", prefix); 102 | println(getWords(n, prefix)); 103 | } 104 | 105 | private static void printAllWords(TrieNode n) { 106 | printf("getAllWords: "); 107 | println(getAllWords(n)); 108 | } 109 | } 110 | --------------------------------------------------------------------------------