diff --git a/src/main/java/arraystring/_01_01_IsUnique.java b/src/main/java/arraystring/_01_01_IsUnique.java index 3544606..97f7ce2 100644 --- a/src/main/java/arraystring/_01_01_IsUnique.java +++ b/src/main/java/arraystring/_01_01_IsUnique.java @@ -1,5 +1,8 @@ package arraystring; +import java.util.Set; +import java.util.stream.Collectors; + /** * Implement an algorithm to determine if a string has all unique characters. */ @@ -7,7 +10,9 @@ class _01_01_IsUnique { boolean isUnique(String str) { - throw new UnsupportedOperationException(); +// long distinctCount = str.chars().boxed().distinct().count(); + Set set = str.chars().boxed().collect(Collectors.toSet()); + return set.size() == str.length(); } } diff --git a/src/main/java/arraystring/_01_02_CheckPermutation.java b/src/main/java/arraystring/_01_02_CheckPermutation.java index eed4b07..85267e2 100644 --- a/src/main/java/arraystring/_01_02_CheckPermutation.java +++ b/src/main/java/arraystring/_01_02_CheckPermutation.java @@ -1,10 +1,21 @@ package arraystring; +import java.util.HashMap; +import java.util.Map; + /** * Given two strings,write a method to decide if one is a permutation of the other. */ class _01_02_CheckPermutation { boolean check(String a, String b) { - throw new UnsupportedOperationException(); + return computeFrequency(a).equals(computeFrequency(b)); + } + + private Map computeFrequency(String s) { + Map freq = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + freq.merge(s.charAt(i), 1, (ov, v) -> ov + v); + } + return freq; } } diff --git a/src/main/java/arraystring/_01_03_URLify.java b/src/main/java/arraystring/_01_03_URLify.java index 56ea4a8..b1ce6cd 100644 --- a/src/main/java/arraystring/_01_03_URLify.java +++ b/src/main/java/arraystring/_01_03_URLify.java @@ -1,5 +1,7 @@ package arraystring; +import java.util.Arrays; + /** * Write a method to replace all spaces in a string with '%20' * You may assume that the string has sufficient space at the end to hold the additional characters, @@ -12,6 +14,38 @@ */ class _01_03_URLify { char[] urlify(char[] chars, int trueLength) { - throw new UnsupportedOperationException(); + int spaces = 0; + for (int i = 0; i < trueLength; i++) { + if (chars[i] == ' ') { + spaces++; + } + } + if ((chars.length - trueLength) != (2 * spaces)) { + throw new IllegalArgumentException("incorrect length " + chars.length + ": " + (trueLength + 2 * spaces) + " required."); + } + /* this my own way is not efficient, the master one is better + int j = trueLength; + for (int i = trueLength; i > 0; i--) { + if (chars[i-1] == ' ') { + char[] tmp = Arrays.copyOfRange(chars, i, j); + chars[i-1] = '%'; + chars[i] = '2'; + chars[i+1] = '0'; + System.arraycopy(tmp, 0, chars, i+2, tmp.length); + j += 2; + } + } + */ + for (int i = trueLength - 1, j = chars.length - 1; i >= 0; i--) { + if (chars[i] == ' ') { + chars[j--] = '0'; + chars[j--] = '2'; + chars[j--] = '%'; + } + else { + chars[j--] = chars[i]; + } + } + return chars; } } diff --git a/src/main/java/arraystring/_01_04_PalindromePermutation.java b/src/main/java/arraystring/_01_04_PalindromePermutation.java index 4b3a295..128e884 100644 --- a/src/main/java/arraystring/_01_04_PalindromePermutation.java +++ b/src/main/java/arraystring/_01_04_PalindromePermutation.java @@ -12,6 +12,22 @@ */ class _01_04_PalindromePermutation { boolean check(String s) { - throw new UnsupportedOperationException(); + char[] chars = s.toCharArray(); + int i = 0, j = s.length() - 1; + while (i < j) { + while (i < j && !Character.isLetterOrDigit(chars[i])) { + i++; + } + while (j > i && !Character.isLetterOrDigit(chars[j])) { + j--; + } + if (i >= j) return true; + if (Character.toLowerCase(chars[i]) != Character.toLowerCase(chars[j])) { + return false; + } + i++; + j--; + } + return true; } } diff --git a/src/main/java/arraystring/_01_05_OneAway.java b/src/main/java/arraystring/_01_05_OneAway.java index 29c3197..d840c10 100644 --- a/src/main/java/arraystring/_01_05_OneAway.java +++ b/src/main/java/arraystring/_01_05_OneAway.java @@ -13,7 +13,35 @@ */ class _01_05_OneAway { boolean isOneAway(String a, String b) { - throw new UnsupportedOperationException(); + int len = a.length(); + if (Math.abs(a.length() - b.length()) == 1) { + char[] shorter = a.length() < b.length() ? a.toCharArray() : b.toCharArray(); + char[] longer = a.length() < b.length() ? b.toCharArray() : a.toCharArray(); + for (int i = 0, j = 0; i < shorter.length; i++) { + while (shorter[i] != longer[j++]) { + if (j > i+1) { + return false; + } + } + } + } + else if (a.length() == b.length()) { + boolean hasDifferent = false; + for (int i = 0; i < a.length(); i ++) { + if (a.charAt(i) != b.charAt(i)) { + if (!hasDifferent) { + hasDifferent = true; + } + else { + return false; + } + } + } + } + else { + return false; + } + return true; } } diff --git a/src/main/java/arraystring/_01_06_StringCompression.java b/src/main/java/arraystring/_01_06_StringCompression.java index 35ac6d3..fd3ac84 100644 --- a/src/main/java/arraystring/_01_06_StringCompression.java +++ b/src/main/java/arraystring/_01_06_StringCompression.java @@ -8,6 +8,146 @@ */ class _01_06_StringCompression { String compress(String s) { - throw new UnsupportedOperationException(); + StringBuilder sb = new StringBuilder(); + char c = ' '; + int count = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) != c) { + if (count > 0) { + sb.append(c).append(count); + } + c = s.charAt(i); + count = 1; + } + else { + count++; + } + } + if (count > 0) { + sb.append(c).append(count); + } + return sb.length() < s.length() ? sb.toString() : s; + } + + /** + * Given an array of characters, compress it in-place. + * + * The length after compression must always be smaller than or equal to the original array. + * + * Every element of the array should be a character (not int) of length 1. + * + * After you are done modifying the input array in-place, return the new length of the array. + * + * Example 1: + * + * Input: + * ["a","a","b","b","c","c","c"] + * + * Output: + * Return 6, and the first 6 characters of the input array should be: ["a","2","b","2","c","3"] + * + * Explanation: + * "aa" is replaced by "a2". "bb" is replaced by "b2". "ccc" is replaced by "c3". + * + * Example 2: + * + * Input: + * ["a"] + * + * Output: + * Return 1, and the first 1 characters of the input array should be: ["a"] + * + * Explanation: + * Nothing is replaced. + * + * Example 3: + * + * Input: + * ["a","b","b","b","b","b","b","b","b","b","b","b","b"] + * + * Output: + * Return 4, and the first 4 characters of the input array should be: ["a","b","1","2"]. + * + * Explanation: + * Since the character "a" does not repeat, it is not compressed. "bbbbbbbbbbbb" is replaced by "b12". + * + * @param chars + * @return + */ + public int compress_leetcode_443(char[] chars) { + if (chars.length <= 1) return chars.length; + char c = chars[0]; + int count = 0; + int j = 0; + for (int i = 1; i <= chars.length; i++) { + if (i < chars.length && chars[i] == c) { // repeating characters + count++; + } + else if (i >= chars.length || c != chars[i]) { // to the end or encounter a new character + chars[j++] = c; + if (count > 0) { + String s = String.valueOf(count + 1); + System.arraycopy(s.toCharArray(), 0, chars, j, s.length()); + j += s.length(); + } + if (i < chars.length) { + c = chars[i]; + count = 0; + } + } + } + return j; + } + + public int compress_leetcode_443_2nd(char[] chars) { + if (chars.length <= 1) return chars.length; + char c = chars[0]; + int count = 0; + int j = 0; + for (int i = 1; i < chars.length; i++) { + if (chars[i] == c) { // count repeating characters + count++; + } + if (i + 1 == chars.length || c != chars[i]) { // to the end of the chars or a different character + chars[j++] = c; // start to output last character + if (count > 0) { // append count of repeating times to the character + String s = String.valueOf(count + 1); + System.arraycopy(s.toCharArray(), 0, chars, j, s.length()); + j += s.length(); + } + if (i + 1 == chars.length && chars[i] != c) { + chars[j++] = chars[i]; + } + c = chars[i]; + count = 0; + } + } + return j; + } + + public int compress_leetcode_443_best(char[] chars) { + int anchor = 0, write = 0; + for (int read = 0; read < chars.length; read++) { + if ((read + 1 == chars.length) || (chars[read + 1] != chars[read])) { + chars[write++] = chars[anchor]; + if (read > anchor) { + for (char c : Integer.toString(read - anchor + 1).toCharArray()) { + chars[write++] = c; + } + } + anchor = read + 1; + } + } + return write; + } + + public static void main(String args[]) { + _01_06_StringCompression solution = new _01_06_StringCompression(); + char[] chars = "aabbcccd".toCharArray(); + int len = solution.compress_leetcode_443(chars); + System.out.println("After compress_mine: " + new String(chars).substring(0, len)); + chars = "aabbcccd".toCharArray(); + len = solution.compress_leetcode_443_best(chars); + System.out.println("After compress_best: " + new String(chars).substring(0, len)); } } diff --git a/src/main/java/arraystring/_01_07_RotateMatrix.java b/src/main/java/arraystring/_01_07_RotateMatrix.java index 774efc0..773a743 100644 --- a/src/main/java/arraystring/_01_07_RotateMatrix.java +++ b/src/main/java/arraystring/_01_07_RotateMatrix.java @@ -3,11 +3,67 @@ /** * Given an image represented by an NxN matrix, where each pixel in the image is 4 bytes, * write a method to rotate the image by 90 degrees. Can you do this in place? + * + * refer to leetcode 48 */ class _01_07_RotateMatrix { int[][] rotate(int[][] m) { - throw new UnsupportedOperationException(); + int start = 0, end = m.length - 1; + while (start < end) { // rotate from outside to inside, each rotation is a level + rotateBoundary(m, start, end); + start++; + end--; + } + return m; } + /** + * rotate the ring area of the matrix bounded by start and end + * @param m the matrix for rotation + * @param start the start index of the boundary + * @param end the end index of the boundary + */ + private void rotateBoundary(int[][] m, int start, int end) { + if (start >= end) { + } + for (int i = start; i < end; i++) { + int x = i, y = start; + int last = m[x][y]; + for (int j = 0; j < 4; j++) { + // new coordinate: + // x' = y + // y' = n - x, here n = matrix size minus 1 + int tmp = x; + x = y; + y = m.length - 1 - tmp; + tmp = m[x][y]; + m[x][y] = last; + last = tmp; + } + } + } + + int[][] rotate_better(int[][] m) { + swapRow(m); + transpose(m); + return m; + } + private void swapRow(int[][] m) { + for (int start = 0, end = m.length - 1; start < end; ++start, ++end) { + int[] tmp = m[start]; + m[start] = m[end]; + m[end] = tmp; + } + } + + private void transpose(int[][] m) { + for (int i = 0; i < m.length; i++) { + for (int j = i + 1; j < m.length; j++) { + int tmp = m[i][j]; + m[i][j] = m[j][i]; + m[j][i] = tmp; + } + } + } } diff --git a/src/main/java/arraystring/_01_08_ZeroMatrix.java b/src/main/java/arraystring/_01_08_ZeroMatrix.java index facd7b2..94f6b3a 100644 --- a/src/main/java/arraystring/_01_08_ZeroMatrix.java +++ b/src/main/java/arraystring/_01_08_ZeroMatrix.java @@ -1,10 +1,76 @@ package arraystring; +import java.util.HashSet; +import java.util.Set; + /** * Write an algorithm such that if an element in an MxN matrix is 0, its entire row and column are set to 0. */ class _01_08_ZeroMatrix { + int[][] zero_mine(int[][] matrix) { + Set clearRows = new HashSet<>(); + Set clearColumns = new HashSet<>(); + for (int i = 0; i < matrix.length; ++i) { + for (int j = 0; j < matrix[0].length; ++j) { + if (matrix[i][j] == 0) { + clearRows.add(i); + clearColumns.add(j); + } + } + } + clearRows.forEach(row -> { + for (int i = 0; i < matrix[0].length; ++i) { + matrix[row][i] = 0; + } + }); + clearColumns.forEach(column -> { + for (int i = 0; i < matrix.length; ++i) { + matrix[i][column] = 0; + } + }); + return matrix; + } + int[][] zero(int[][] matrix) { - throw new UnsupportedOperationException(); + int rows = matrix.length; + int columns = matrix[0].length; + if (columns == 0) return matrix; + boolean firstColumn = false; + for (int i = 0; i < rows; ++i) { + if (matrix[i][0] == 0) { + // for the first column we don't change the matrix[0][0] to 0 + // as it holds the zero indication for both first row and first column + // instead, additional variable is used to mark the zero first column + // as a result, matrix[0][0] is used to mark zero first row only + firstColumn = true; + } + for (int j = 1; j < columns; ++j) { + if (matrix[i][j] == 0) { + matrix[i][0] = 0; + matrix[0][j] = 0; + } + } + } + for (int i = 1; i < rows; ++i) { + for (int j = 1; j < columns; ++j) { + if (matrix[i][0] == 0 || matrix[0][j] == 0) { + matrix[i][j] = 0; + } + } + } + // deal with the first row + if (matrix[0][0] == 0) { + for (int j = 1; j < columns; ++j) { + matrix[0][j] = 0; + } + } + + // deal with the first column + if (firstColumn) { + for (int i = 0; i < rows; ++i) { + matrix[i][0] = 0; + } + } + return matrix; } } diff --git a/src/main/java/arraystring/_01_09_StringRotation.java b/src/main/java/arraystring/_01_09_StringRotation.java index b10bc05..02e44d6 100644 --- a/src/main/java/arraystring/_01_09_StringRotation.java +++ b/src/main/java/arraystring/_01_09_StringRotation.java @@ -7,7 +7,29 @@ */ class _01_09_StringRotation { boolean rotated(String original, String result) { - throw new UnsupportedOperationException(); + if (original.equalsIgnoreCase(result)) { + return true; + } + if (original.length() != result.length()) { + return false; + } + int SIZE = original.length(); + int start = 1; // the string is not matched, so start from the second character + while (start < SIZE) { + if (result.charAt(start) == original.charAt(0)) { + boolean matched = true; + for (int i = 1; i < SIZE; ++i) { + int offset = (start + i) % SIZE; + if (original.charAt(i) != result.charAt(offset)) { + matched = false; + break; + } + } + if (matched) return true; + } + ++start; + } + return false; } } diff --git a/src/main/java/bitmanipulation/_05_01_Insertion.java b/src/main/java/bitmanipulation/_05_01_Insertion.java index 2ec0139..be5c3a8 100644 --- a/src/main/java/bitmanipulation/_05_01_Insertion.java +++ b/src/main/java/bitmanipulation/_05_01_Insertion.java @@ -1,5 +1,7 @@ package bitmanipulation; +import java.util.BitSet; + /** * You are given two 32-bit numbers, N and M, and two bit positions, i and j. * Write a method to insert M into N such that M starts at bit j and ends at bit i. @@ -14,6 +16,28 @@ class _05_01_Insertion { int insert(int n, int m, int i, int j) { - throw new UnsupportedOperationException(); + printBits(n); + printBits(m); + int allOnes = -1; + int left = allOnes << (j + 1); + int right = (1 << i) - 1; + int mask = left | right; + int offset = m << i; + int cleared = n & mask; + int result = cleared | offset; + printBits(result); + return result; + } + + private void printBits(int n) { + System.out.print(n + ": "); + int mask = 1 << 31; // get "10000000 00000000 00000000 00000000" + for (int i = 1; i <= 32; ++i, n <<= 1) { + System.out.print((n & mask) == 0 ? "0" : "1"); + if (i % 8 == 0) { + System.out.print(" "); + } + } + System.out.println(); } } diff --git a/src/main/java/bitmanipulation/_05_02_BinaryToString.java b/src/main/java/bitmanipulation/_05_02_BinaryToString.java index 0555c98..fc85431 100644 --- a/src/main/java/bitmanipulation/_05_02_BinaryToString.java +++ b/src/main/java/bitmanipulation/_05_02_BinaryToString.java @@ -6,6 +6,15 @@ */ class _05_02_BinaryToString { String print(double num) { - throw new UnsupportedOperationException(); + if (num < 0 || num > 1) { + return "ERROR:"; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < 32; ++i) { + if (num == 0) { + + } + } + return "ERROR:"; } } diff --git a/src/main/java/bitmanipulation/_05_03_FlipBitToWin.java b/src/main/java/bitmanipulation/_05_03_FlipBitToWin.java index bfdb9c0..ab3e509 100644 --- a/src/main/java/bitmanipulation/_05_03_FlipBitToWin.java +++ b/src/main/java/bitmanipulation/_05_03_FlipBitToWin.java @@ -1,5 +1,8 @@ package bitmanipulation; +import java.util.ArrayList; +import java.util.List; + /** * You have an integer and you can flip exactly one bit from a 0 to a 1. * Write code to find the length of the longest sequence of 1s you could create. @@ -10,6 +13,82 @@ */ class _05_03_FlipBitToWin { int flip(int n) { - throw new UnsupportedOperationException(); + /* + int num = 0; + for (byte i = 0; i < 32; ++i) { + boolean isZero = isZeroAt(n, i); + if (isZero) { + int len = getMaxLengthOfOnes(n, i); + if (len > num) { + num = len; + } + } + } + if (num == 0) { + // there is no zero in the binary representation + num = 32; + } + System.out.println("The answer to number " + n + " is " + num); + return num; + */ + + return sampleSolution(n); + } + + private boolean isZeroAt(int n, byte pos) { + int mask = 1 << pos; + return (n & mask) == 0; + } + + private int getMaxLengthOfOnes(int n, byte flipOn) { + int len = 0; + int maxLen = len; + int mask = 1; + for (byte i = 0; i < 32; ++i, mask <<= 1) { + if ((n & mask) != 0 || i == flipOn) { + ++len; + } else { + if (len > maxLen) { + maxLen = len; + } + len = 0; + } + } + System.out.println(String.format("Flipping to %d(%s) @%d got %d 1s", n, toBinaryString(n), flipOn, maxLen)); + return maxLen; + } + + private static String toBinaryString(int n) { + int mask = Integer.MIN_VALUE; + StringBuilder sb = new StringBuilder(); + for (byte i = 1; i <= 32; ++i) { + sb.append((n & mask) == 0 ? "0" : "1"); + if (i % 8 == 0) { + sb.append(' '); + } + mask >>>= 1; + } + return sb.toString(); + } + + private static int sampleSolution(int n) { + if (n == -1) { + return 32; + } + int pre = 0; + int cur = 0; + int max = 1; + while (n != 0) { + if ((n & 1) == 1) { + ++cur; + } else { + // check if the next bit is "0", which means current counting is not applicable for next round of count + pre = (n & 2) == 0 ? 0 : cur; + cur = 0; + } + max = Math.max(max, pre + cur + 1); + n >>>= 1; + } + return max; } } diff --git a/src/main/java/geek/math/MathLesson10_DynamicProgramming.java b/src/main/java/geek/math/MathLesson10_DynamicProgramming.java new file mode 100644 index 0000000..bf5da3a --- /dev/null +++ b/src/main/java/geek/math/MathLesson10_DynamicProgramming.java @@ -0,0 +1,90 @@ +package geek.math; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class MathLesson10_DynamicProgramming { + /** + * Calculate the edit distance of two words + * This is pretty much same with arraystring._01_05_OneAway + * + * @param a + * @param b + * @return + */ + public static int getStrDistance(String a, String b) { + if (a == null || b == null) { + return -1; + } + int[][] d = new int[a.length() + 1][b.length() + 1]; + for (int i = 0; i <= a.length(); ++i) { + d[i][0] = i; + } + for (int j = 0; j <= b.length(); ++j) { + d[0][j] = j; + } + for (int i = 1; i <= a.length(); ++i) { + for (int j = 1; j <= b.length(); ++j) { + int r = d[i-1][j-1] + (a.charAt(i-1) == b.charAt(j-1) ? 0 : 1); + int appendA = d[i-1][j] + 1; + int appendB = d[i][j-1] + 1; + d[i][j] = Math.min(r, Math.min(appendA, appendB)); + } + } + // for debug purpose +// System.out.println(Arrays.deepToString(d)); + return d[a.length()][b.length()]; + } + + /** + * Get the least notes required to collect the sum of money + * + * @param values the values of notes we have + * @param amount the amount of money we want to collect + * @return + */ + public static int getLeastNotes(int[] values, int amount) { + if (values == null || values.length < 1) { + return -1; + } + Arrays.sort(values); + List counts = new ArrayList<>(); + for (int i = 1; i <= amount; ++i) { + int result = 0; + // pick the best solution: the smallest count + for (int j = 0; j < values.length; ++j) { + int count = getCountForNote(values[j], counts); + if (result == 0 || (count > 0 && result > count)) { + result = count; + } + } + counts.add(result); + } + System.out.println(counts.toString()); + return counts.get(counts.size() - 1); + } + + /** + * Get the count of notes if we choose to pick this note + * + * @param noteValue the value of the note we picked + * @param counts the list of previous least counts we got + * @return + */ + private static int getCountForNote(int noteValue, List counts) { + // the amount we want to collect + int amount = counts.size() + 1; + if (amount < noteValue) { + // impossible to collect this note to satisfy the amount + return 0; + } + if (amount == noteValue) { + // the note value matches the amount, this is certainly the least count + return 1; + } + int preCount = counts.get(amount - noteValue - 1); + // count == 0 means there is no solution to this amount + return preCount == 0 ? 0 : preCount + 1; + } +} diff --git a/src/main/java/geek/math/MathLesson12_Trie.java b/src/main/java/geek/math/MathLesson12_Trie.java new file mode 100644 index 0000000..6b42b15 --- /dev/null +++ b/src/main/java/geek/math/MathLesson12_Trie.java @@ -0,0 +1,179 @@ +package geek.math; + +import java.util.*; + +public class MathLesson12_Trie { + TreeNode root = new TreeNode(Character.MIN_VALUE, null, null); + + public void put(String word, String explaination) { + TreeNode curr = root; + char[] chars = word.toCharArray(); + for (char c : chars) { + curr = getSon(curr, c, true); + }; + curr.explanation = explaination; + } + + public TreeNode find(String word) { + TreeNode found = null; + char[] chars = word.toCharArray(); + TreeNode curr = root; + for (char c : chars) { + curr = getSon(curr, c, false); + if (curr == null) { + break; + } + } + return curr; + } + + private static TreeNode getSon(TreeNode parent, char c, boolean createIfNotFound) { + TreeNode found = null; + if (parent.sons != null && parent.sons.containsKey(c)) { + found = parent.sons.get(c); + } else if (createIfNotFound) { + String prefix = parent.prefix == null ? "" : parent.prefix + parent.label; + found = new TreeNode(c, prefix, null); + parent.offer(found); + } + return found; + } + + /** + * Depth First Search to traverse the tree and print all words in order + * + * @return list of words + */ + public List dfsTraverse() { + if (root == null) { + return null; + } + return dfsWords(root); + } + + private static List dfsWords(TreeNode node) { + if (node.sons == null || node.sons.isEmpty()) { + // leave node, return it + List leaveWord = new ArrayList<>(); + if (node.label != Character.MIN_VALUE) { + leaveWord.add(node.prefix + node.label); + } + return leaveWord; + } + List results = new ArrayList<>(); + if (node.explanation != null) { + results.add(node.prefix + node.label); + } + Character[] chars = node.sons.keySet().toArray(new Character[node.sons.size()]); + Arrays.sort(chars); + for (char c : chars) { + results.addAll(dfsWords(node.sons.get(c))); + } + return results; + } + + /** + * traverse all nodes in order using stack + * + * @return + */ + public List dfsTraverseByStack() { + if (root == null) { + return null; + } + List results = new ArrayList<>(); + Stack stack = new Stack<>(); + stack.push(root); + while (!stack.empty()) { + TreeNode node = stack.pop(); + if (node.explanation != null) { + results.add(node.prefix + node.label); + } + if (node.sons == null || node.sons.isEmpty()) { + continue; + } + Character[] chars = node.sons.keySet().toArray(new Character[node.sons.size()]); + Arrays.sort(chars); + for (int i = chars.length - 1; i >= 0; --i) { + stack.push(node.sons.get(chars[i])); + } + } + return results; + } + + /** + * BFS traverse + * + * @return + */ + public List bfsTraverse() { + if (root == null) { + return null; + } + List results = new ArrayList<>(); + LinkedList queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + if (node.explanation != null) { + results.add(node.prefix + node.label); + } + if (node.sons == null || node.sons.isEmpty()) { + continue; + } + Character[] chars = node.sons.keySet().toArray(new Character[node.sons.size()]); + Arrays.sort(chars); + for (char c : chars) { + queue.offer(node.sons.get(c)); + } + } + return results; + } + + @Override + public String toString() { + List words = dfsTraverse(); + StringBuilder sb = new StringBuilder("Dictionary Words:\n"); + words.forEach(w -> sb.append("\t").append(w).append("\n")); + sb.append("[END]\n"); + return sb.toString(); + } +} + +class TreeNode { + char label; + HashMap sons; + String prefix; + String explanation; + + public TreeNode(char label, String prefix, String explanation) { + this.label = label; + this.prefix = prefix; + this.explanation = explanation; + } + + void offer(TreeNode node) { + if (sons == null) { + sons = new HashMap<>(26); + } + sons.put(node.label, node); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + if (label == Character.MIN_VALUE) { + sb.append("[ROOT]\n"); + } else { + sb.append("[").append(prefix).append(label).append("]"); + if (explanation != null) { + sb.append(" - Explanation:").append(explanation); + } + sb.append("\n"); + } + if (sons != null) { + sons.keySet().stream().sorted().forEach(c -> sb.append(sons.get(c).toString())); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/geek/math/MathLesson14_Graph.java b/src/main/java/geek/math/MathLesson14_Graph.java new file mode 100644 index 0000000..c2b5a67 --- /dev/null +++ b/src/main/java/geek/math/MathLesson14_Graph.java @@ -0,0 +1,178 @@ +package geek.math; + +import java.util.*; + +public class MathLesson14_Graph { + + public MathLesson14_Graph(int size) { + nodes = new Node[size]; + this.size = size; + } + + public MathLesson14_Graph() { + init(10, 15); + } + + Node[] nodes; + + int size; + + public void init(int size, int relationCount) { + nodes = new Node[size]; + this.size = size; + for (int i = 0; i < size; ++i) { + nodes[i] = new Node(i); + } + Random random = new Random(); + for (int i = 0; i < relationCount; ++i) { + int idA = random.nextInt(size); + int idB = random.nextInt(size); + if (idA == idB) { + continue; + } + Node nodeA = nodes[idA]; + Node nodeB = nodes[idB]; + nodeA.friends.add(idB); + nodeB.friends.add(idA); + } + } + + public MathLesson14_Graph append(Node user) { + if (user == null || user.userId < 0) { + throw new IllegalArgumentException("illegal user"); + } + if (user.userId >= this.size) { + throw new IllegalStateException("limit on capability"); + } + nodes[user.userId] = user; + return this; + } + + public List bfs(int userId) { + if (userId > nodes.length) { + throw new IllegalArgumentException(userId + " is out of range"); + } + List result = new ArrayList<>(); + Node user = nodes[userId]; + System.out.println("Get friends of user " + userId); + Queue people = new LinkedList<>(); + people.offer(userId); + // record each visited user's degree + Map degrees = new HashMap<>(); + degrees.put(userId, 0); + List friends = new ArrayList<>(); + int lastDegree = 1; + while (!people.isEmpty()) { + Node curr = nodes[people.poll()]; + // all nodes under this node will have the same degree, adding by 1 from the current node + int degree = degrees.get(curr.userId) + 1; + if (degree > lastDegree && !friends.isEmpty()) { + result.add(friends.toArray(new Integer[friends.size()])); + System.out.println("Friends of degree #" + lastDegree + ": " + friends.toString()); + friends.clear(); + lastDegree = degree; + } + curr.friends.stream().filter(id -> !degrees.containsKey(id)).forEach(id -> { + degrees.put(id, degree); + people.offer(id); + friends.add(id); + }); + } + if (!friends.isEmpty()) { + result.add(friends.toArray(new Integer[friends.size()])); + System.out.println("Friends of degree #" + lastDegree + ": " + friends.toString()); + } + return result; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("MathLesson14_Graph size : " + size + "\n"); + for (Node node : nodes) { + sb.append(node.toString()).append("\n"); + } + return sb.toString(); + } + + public int distance(int a, int b) { + if (a >= this.size || b >= this.size) { + return -1; + } + if (a == b) { + return 0; + } + Map degreeMapA = new HashMap<>(); + degreeMapA.put(a, 0); + Map degreeMapB = new HashMap<>(); + degreeMapB.put(b, 0); + Queue queueA = new LinkedList<>(); + Queue queueB = new LinkedList<>(); + queueA.offer(a); + queueB.offer(b); + final int MAX_DEGREE = 10; + int degreeA = 0, degreeB = 0; + while ((degreeA + degreeB) < MAX_DEGREE && (!queueA.isEmpty() || !queueB.isEmpty())) { + degreeA = getNextDegreeFriends(queueA, degreeA, degreeMapA); + if (!Collections.disjoint(degreeMapA.keySet(), degreeMapB.keySet())) { + return degreeA + degreeB; + } + degreeB = getNextDegreeFriends(queueB, degreeB, degreeMapB); + if (!Collections.disjoint(degreeMapA.keySet(), degreeMapB.keySet())) { + return degreeA + degreeB; + } + } + return -1; + } + + private int getNextDegreeFriends(Queue queue, int degree, Map map) { + int count = queue.size(); + if (count == 0) { + return degree; + } + int newDegree = degree; + for (int i = 0; i < count; ++i) { + int id = queue.poll(); + Node node = nodes[id]; + if (node.friends != null) { + Iterator iter = node.friends.iterator(); + while (iter.hasNext()) { + int uid = iter.next(); + if (map.get(uid) != null) { + continue; + } else { + newDegree = degree + 1; + queue.offer(uid); + map.put(uid, newDegree); + } + }; + } + } + return newDegree; + } +} + +class Node { + public int userId; + public HashSet friends = null; + + public Node(int id) { + this.userId = id; + this.friends = new HashSet<>(); + } + + public Node(int userId, int[] friends) { + this.userId = userId; + this.friends = new HashSet<>(); + for (int i : friends) { + this.friends.add(i); + } + } + + @Override + public String toString() { + return "Node{" + + "userId=" + userId + + ", friends=" + friends + + '}'; + } +} \ No newline at end of file diff --git a/src/main/java/geek/math/MathLesson15_Dijkstra.java b/src/main/java/geek/math/MathLesson15_Dijkstra.java new file mode 100644 index 0000000..c86db8e --- /dev/null +++ b/src/main/java/geek/math/MathLesson15_Dijkstra.java @@ -0,0 +1,157 @@ +package geek.math; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class MathLesson15_Dijkstra { + + int size = 0; + DijkstraVertex[] vertices; + + public MathLesson15_Dijkstra(int size) { + this.size = size; + vertices = new DijkstraVertex[size]; + } + + public double getBestPath(int a, int b) { + if (a < 0 || b < 0 || a >= vertices.length || b >= vertices.length) { + throw new IllegalArgumentException("source or target out of range"); + } + if (vertices[a] == null || vertices[b] == null) { + throw new IllegalArgumentException("source or target does not exist"); + } + if (a == b) { + System.out.println("The shortest path from " + a + " to " + b + ": 0"); + return 0.0; + } + Set set = new HashSet<>(); + Map dist = new HashMap<>(); + Map prev = new HashMap<>(); + for (DijkstraVertex v : vertices) { + dist.put(v.id, Double.POSITIVE_INFINITY); + prev.put(v.id, Integer.MAX_VALUE); + set.add(v); + } + dist.put(a, 0.0); + while (!set.isEmpty()) { + DijkstraVertex shortest = getShortestVertex(set, dist); + if (shortest == null) { + // cannot find connected vertex + break; + } + set.remove(shortest); + Integer id = shortest.id; + Double p = dist.get(id); + if (p == Double.POSITIVE_INFINITY) { + break; + } + if (shortest.connections != null) { + shortest.connections.forEach((k,v) -> { + Double distance = p + v; + if (distance < dist.get(k)) { + dist.put(k, distance); + prev.put(k, id); + } + }); + } + } + System.out.println("The shortest path from " + a + " to " + b + ":"); + if (dist.get(b) != Double.POSITIVE_INFINITY) { + Double result = dist.get(b); + List path = getPath(a, b, prev); + path.forEach(v -> System.out.print(String.format("%d(%.2f) ", v.id, dist.get(v.id)))); + System.out.print("\n"); + return result; + } else { + System.out.println("None"); + return Double.NEGATIVE_INFINITY; + } + } + + private List getPath(int a, int b, Map prev) { + // assume a and b are valid here as it is a private method + List path = new ArrayList<>(); + int curr = b; + while (curr != Integer.MAX_VALUE) { + path.add(vertices[curr]); + curr = prev.get(curr); + } + Collections.reverse(path); + return path; + } + + private static DijkstraVertex getShortestVertex(Collection c, Map dist) { + if (c == null) { + return null; + } + Double min = Double.POSITIVE_INFINITY; + DijkstraVertex chosen = null; + for (DijkstraVertex v : c) { + Double d = dist.get(v.id); + if (d < min) { + chosen = v; + min = d; + } + } + return chosen; + } +} + +class DijkstraVertex { + int id; + Map connections; + + public DijkstraVertex(int id) { + this.id = id; + } + + public void addConnection(int id, double weight) { + if (connections == null) { + connections = new HashMap<>(); + } + connections.put(id, weight); + } + + public void setConnections(Map connections) { + this.connections = connections; + } + + private static Pattern pattern = Pattern.compile("^(\\d+)\\s*(\\(.*\\))?$"); + private static Pattern connection_pattern = Pattern.compile("\\s*(\\(\\s*(\\d+)\\s*,\\s*([0-9]*[.]?[0-9]+)\\s*\\))\\s*"); + + public static DijkstraVertex parse(String content) { + Matcher matcher = pattern.matcher(content); + if (matcher.find()) { + int id = Integer.valueOf(matcher.group(1)); + String connectionParts = matcher.group(2); + DijkstraVertex v = new DijkstraVertex(id); + if (connectionParts != null) { + Matcher m2 = connection_pattern.matcher(connectionParts); + while (m2.find()) { + int vid = Integer.valueOf(m2.group(2)); + double w = Double.valueOf(m2.group(3)); + v.addConnection(vid, w); + } + } + return v; + } else { + return null; + } + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DijkstraVertex that = (DijkstraVertex) o; + return id == that.id && + Objects.equals(connections, that.connections); + } + + @Override + public int hashCode() { + return Objects.hash(id, connections); + } +} \ No newline at end of file diff --git a/src/main/java/linkedlist/_02_01_RemoveDups.java b/src/main/java/linkedlist/_02_01_RemoveDups.java index da5f5ef..4c3f5e2 100644 --- a/src/main/java/linkedlist/_02_01_RemoveDups.java +++ b/src/main/java/linkedlist/_02_01_RemoveDups.java @@ -1,5 +1,8 @@ package linkedlist; +import java.util.HashSet; +import java.util.Set; + /** * Remove Dups! * Write code to remove duplicates from an unsorted linked list. @@ -7,6 +10,18 @@ class _02_01_RemoveDups { LinkedListNode removeDups(LinkedListNode head) { - throw new UnsupportedOperationException(); + Set set = new HashSet<>(); + LinkedListNode prev = null; + LinkedListNode curr = head; + while (curr != null) { + if (set.contains(curr.val)) { + prev.next = curr.next; + } else { + set.add(curr.val); + } + prev = curr; + curr = curr.next; + } + return head; } } diff --git a/src/main/java/linkedlist/_02_02_ReturnKthToLast.java b/src/main/java/linkedlist/_02_02_ReturnKthToLast.java index 50d10cc..f6eefee 100644 --- a/src/main/java/linkedlist/_02_02_ReturnKthToLast.java +++ b/src/main/java/linkedlist/_02_02_ReturnKthToLast.java @@ -1,11 +1,23 @@ package linkedlist; +import java.util.LinkedList; +import java.util.Queue; + /** * Implement an algorithm to find the kth to last element of a singly linked list */ class _02_02_ReturnKthToLast { LinkedListNode kthToLast(LinkedListNode head, int k) { - throw new UnsupportedOperationException(); + Queue deque = new LinkedList<>(); + LinkedListNode curr = head; + while (curr != null) { + if (deque.size() >= (k + 1)) { + deque.remove(); + } + deque.add(curr); + curr = curr.next; + } + return deque.size() > k ? deque.remove() : null; } } diff --git a/src/main/java/linkedlist/_02_03_DeleteMiddleNode.java b/src/main/java/linkedlist/_02_03_DeleteMiddleNode.java index 5d8bc1c..2fdba86 100644 --- a/src/main/java/linkedlist/_02_03_DeleteMiddleNode.java +++ b/src/main/java/linkedlist/_02_03_DeleteMiddleNode.java @@ -8,6 +8,12 @@ class _02_03_DeleteMiddleNode { boolean deleteMiddleNode(LinkedListNode node) { - throw new UnsupportedOperationException(); + if (node == null || node.next == null) { + return false; + } + LinkedListNode next = node.next; + node.val = next.val; + node.next = next.next; + return true; } } diff --git a/src/main/java/linkedlist/_02_04_Partition.java b/src/main/java/linkedlist/_02_04_Partition.java index 3824dfe..e7bb157 100644 --- a/src/main/java/linkedlist/_02_04_Partition.java +++ b/src/main/java/linkedlist/_02_04_Partition.java @@ -13,6 +13,22 @@ class _02_04_Partition { LinkedListNode partition(LinkedListNode head, int x) { - throw new UnsupportedOperationException(); + if (head == null) { + return null; + } + LinkedListNode pre = null; + LinkedListNode cur = head; + while (cur != null) { + if (cur.val < x && pre != null) { + pre.next = cur.next; + cur.next = head; + head = cur; + cur = pre.next; + } else { + pre = cur; + cur = cur.next; + } + } + return head; } } diff --git a/src/main/java/linkedlist/_02_05_SumList.java b/src/main/java/linkedlist/_02_05_SumList.java index dc333f4..3e2b15e 100644 --- a/src/main/java/linkedlist/_02_05_SumList.java +++ b/src/main/java/linkedlist/_02_05_SumList.java @@ -13,7 +13,31 @@ class _02_05_SumList { LinkedListNode sum(LinkedListNode l1, LinkedListNode l2) { - throw new UnsupportedOperationException(); + if (l1 == null && l2 == null) return null; + int sum = getNumber(l1) + getNumber(l2); + String str = String.valueOf(sum); + LinkedListNode head = null; + LinkedListNode prev = head; + for (char c : str.toCharArray()) { + LinkedListNode digit = new LinkedListNode(c - '0'); + if (prev == null) { + head = digit; + prev = head; + } else { + prev.next = digit; + prev = prev.next; + } + } + return head; } + private static int getNumber(LinkedListNode head) { + LinkedListNode cur = head; + int ret = 0; + while (cur != null) { + ret = ret * 10 + cur.val; + cur = cur.next; + } + return ret; + } } diff --git a/src/main/java/linkedlist/_02_05_SumListReverse.java b/src/main/java/linkedlist/_02_05_SumListReverse.java index 2767df6..55a86f9 100644 --- a/src/main/java/linkedlist/_02_05_SumListReverse.java +++ b/src/main/java/linkedlist/_02_05_SumListReverse.java @@ -12,6 +12,25 @@ */ class _02_05_SumListReverse { LinkedListNode sum(LinkedListNode l1, LinkedListNode l2) { - throw new UnsupportedOperationException(); + if (l1 == null && l2 == null) { + return null; + } + LinkedListNode head = new LinkedListNode(0); + LinkedListNode pre = null; + LinkedListNode tail = head; + while (l1 != null || l2 != null) { + int sum = (l1 == null ? 0 : l1.val) + (l2 == null ? 0 : l2.val); + tail.val += sum % 10; + tail.next = new LinkedListNode(sum / 10); + l1 = l1 == null ? null : l1.next; + l2 = l2 == null ? null : l2.next; + pre = tail; + tail = tail.next; + } + if (tail.val == 0) { + pre.next = null; + } + return head; } + } diff --git a/src/main/java/linkedlist/_02_07_Intersection.java b/src/main/java/linkedlist/_02_07_Intersection.java index e31ddd4..5780202 100644 --- a/src/main/java/linkedlist/_02_07_Intersection.java +++ b/src/main/java/linkedlist/_02_07_Intersection.java @@ -9,6 +9,29 @@ class _02_07_Intersection { boolean intersects(LinkedListNode l1, LinkedListNode l2) { - throw new UnsupportedOperationException(); + if (l1 == null || l2 == null) return false; + LinkedListNode r1 = l1; + LinkedListNode r2 = l2; + boolean switched1 = false; + boolean switched2 = false; + while (r1 != null || r2 != null) { + if (r1 == r2) return true; + if (r1 == null) { + if (switched1) return false; + r1 = l2; + switched1 = true; + } else { + r1 = r1.next; + } + + if (r2 == null) { + if (switched2) return false; + r2 = l1; + switched2 = true; + } else { + r2 = r2.next; + } + } + return false; } } diff --git a/src/main/java/sortingsearching/_10_01_SortedMerge.java b/src/main/java/sortingsearching/_10_01_SortedMerge.java index fad044e..be773d2 100644 --- a/src/main/java/sortingsearching/_10_01_SortedMerge.java +++ b/src/main/java/sortingsearching/_10_01_SortedMerge.java @@ -1,5 +1,9 @@ package sortingsearching; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + /** * You are given two sorted arrays, A and B, where A has a large enough buffer at the end to hold B. * Write a method to merge B into A in sorted order. @@ -7,6 +11,45 @@ public class _10_01_SortedMerge { int[] merge(int[] big, int[] small) { - throw new UnsupportedOperationException(); +// return myway(big, small); + return master(big, small); + } + + private int[] master(int[] big, int[] small) { + int b = big.length - small.length - 1; + int s = small.length - 1; + int t = big.length - 1; + while (b >= 0 || s >=0) { + if (b < 0) { + big[t--] = small[s--]; + } else if (s < 0 || big[b] > small[s]) { + big[t--] = big[b--]; + } else { + big[t--] = small[s--]; + } + } + return big; + } + + private int[] myway(int[] big, int[] small) { + List list = new ArrayList<>(); + int i = 0, j = 0; + while (big[i] != 0 && j < small.length) { + if (big[i] < small[j]) { + list.add(big[i++]); + } else { + list.add(small[j++]); + } + } + while (big[i] != 0) { + list.add(big[i++]); + } + while (j < small.length) { + list.add(small[j++]); + } + for (int m = 0; m < list.size(); ++m) { + big[m] = list.get(m); + } + return big; } } diff --git a/src/main/java/sortingsearching/_10_02_GroupAnagrams.java b/src/main/java/sortingsearching/_10_02_GroupAnagrams.java index 77b0035..16a5b8a 100644 --- a/src/main/java/sortingsearching/_10_02_GroupAnagrams.java +++ b/src/main/java/sortingsearching/_10_02_GroupAnagrams.java @@ -1,6 +1,7 @@ package sortingsearching; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; /** * Write a method to sort an array of strings so that all the anagrams are next to each other. @@ -12,7 +13,18 @@ public class _10_02_GroupAnagrams { * space o(n) */ List groupAnagrams(List words) { - throw new UnsupportedOperationException(); + Map> group = new HashMap<>(); + for (String word : words) { + String sorted = sortedString(word); + group.computeIfAbsent(sorted, k -> new ArrayList<>()).add(word); + } + return group.values().stream().flatMap(List::stream).collect(Collectors.toList()); + } + + private String sortedString(String str) { + char[] chars = str.toCharArray(); + Arrays.sort(chars); + return new String(chars); } } diff --git a/src/main/java/sortingsearching/_10_03_SearchInRotatedArray.java b/src/main/java/sortingsearching/_10_03_SearchInRotatedArray.java index 0b84f95..0688433 100644 --- a/src/main/java/sortingsearching/_10_03_SearchInRotatedArray.java +++ b/src/main/java/sortingsearching/_10_03_SearchInRotatedArray.java @@ -10,7 +10,53 @@ public class _10_03_SearchInRotatedArray { int find(int[] arr, int target) { - throw new UnsupportedOperationException(); + return findRotate(arr, 0, arr.length - 1, target); + } + + private int findRotate(int[] arr, int low, int high, int target) { + if (low >= high) { + return arr[low] == target ? low : -1; + } + int mid = low + (high - low) / 2; + if (arr[mid] == target) { + return mid; + } + if (arr[low] < arr[mid]) { + // left part is ordered + int found = binarySearch(arr, low, mid - 1, target); + if (found >= 0) { + return found; + } + found = findRotate(arr, mid + 1, high, target); + if (found >= 0) { + return found; + } + } else { + int found = findRotate(arr, low, mid - 1, target); + if (found >= 0) { + return found; + } + found = binarySearch(arr, mid + 1, high, target); + if (found >= 0) { + return found; + } + } + return -1; + } + + private int binarySearch(int[] arr, int low, int high, int target) { + while (low <= high) { + int mid = low + ((high - low) >> 1); + if (arr[mid] == target) { + return mid; + } + if (arr[mid] < target) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return -1; } } diff --git a/src/test/java/arraystring/_01_04_PalindromePermutationTest.java b/src/test/java/arraystring/_01_04_PalindromePermutationTest.java index 814f3e0..0bc1f7f 100644 --- a/src/test/java/arraystring/_01_04_PalindromePermutationTest.java +++ b/src/test/java/arraystring/_01_04_PalindromePermutationTest.java @@ -20,16 +20,16 @@ public void withOneChar() { @Test public void withTwoWords_OddLetters() { - assertTrue(s.check("acto tac")); + assertTrue(s.check("acto tca")); } @Test public void withTwoWords_OddLetters_ThreeOccurences() { - assertTrue(s.check("act atac")); + assertTrue(s.check("act atca")); } @Test public void withTwoWords_EvenLetters() { - assertTrue(s.check("act cat")); + assertTrue(s.check("act tca")); } } \ No newline at end of file diff --git a/src/test/java/arraystring/_01_06_StringCompressionTest.java b/src/test/java/arraystring/_01_06_StringCompressionTest.java index eabcaa6..6746000 100644 --- a/src/test/java/arraystring/_01_06_StringCompressionTest.java +++ b/src/test/java/arraystring/_01_06_StringCompressionTest.java @@ -20,7 +20,7 @@ public void withTwoChars() { @Test public void withThreeChars() { - assertEquals("3a", s.compress("aaa")); + assertEquals("a3", s.compress("aaa")); } @Test @@ -30,12 +30,12 @@ public void withDifferentChars() { @Test public void withDifferentChars_RepeatingSeveralTimes() { - assertEquals("3a2b", s.compress("aaabb")); + assertEquals("a3b2", s.compress("aaabb")); } @Test public void withDifferentChars_RepeatingInMoreSeqs() { - assertEquals("3a2b2a", s.compress("aaabbaa")); + assertEquals("a3b2a2", s.compress("aaabbaa")); } } \ No newline at end of file diff --git a/src/test/java/arraystring/_01_07_RotateMatrixTest.java b/src/test/java/arraystring/_01_07_RotateMatrixTest.java index 9b5a35e..625de50 100644 --- a/src/test/java/arraystring/_01_07_RotateMatrixTest.java +++ b/src/test/java/arraystring/_01_07_RotateMatrixTest.java @@ -37,4 +37,20 @@ public void withThreeThree() { {4, 5, 6}, {7, 8, 9}}))); } + + @Test + public void withFourThree() { + assertTrue(Arrays.deepEquals(new int[][]{ + {15,13,2, 5}, + {14,3, 4, 1}, + {12,6, 8, 9}, + {16,7, 10,11} + }, + s.rotate(new int[][]{ + {5, 1, 9, 11}, + {2, 4, 8, 10}, + {13,3, 6, 7}, + {15,14,12,16} + }))); + } } \ No newline at end of file diff --git a/src/test/java/arraystring/_01_08_ZeroMatrixTest.java b/src/test/java/arraystring/_01_08_ZeroMatrixTest.java index 3361eaa..3c3e852 100644 --- a/src/test/java/arraystring/_01_08_ZeroMatrixTest.java +++ b/src/test/java/arraystring/_01_08_ZeroMatrixTest.java @@ -46,4 +46,10 @@ public void withThreeTree() { {4, 0, 6}, {7, 8, 9}}))); } + + // add test case from leetcode 73 + @Test + public void withTwoOne() { + assertTrue(Arrays.deepEquals(new int[][]{{0}, {0}}, new _01_08_ZeroMatrix().zero(new int[][]{{1}, {0}}))); + } } \ No newline at end of file diff --git a/src/test/java/geek/math/MathLesson10_DynamicProgrammingTest.java b/src/test/java/geek/math/MathLesson10_DynamicProgrammingTest.java new file mode 100644 index 0000000..7e94d78 --- /dev/null +++ b/src/test/java/geek/math/MathLesson10_DynamicProgrammingTest.java @@ -0,0 +1,33 @@ +package geek.math; + +import geek.math.MathLesson10_DynamicProgramming; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class MathLesson10_DynamicProgrammingTest { + + @Test + public void getStrDistance() { + assertEquals(1, MathLesson10_DynamicProgramming.getStrDistance("mouse", "mouuse")); + assertEquals(0, MathLesson10_DynamicProgramming.getStrDistance("test", "test")); + assertEquals(1, MathLesson10_DynamicProgramming.getStrDistance("extension", "extention")); + assertEquals(2, MathLesson10_DynamicProgramming.getStrDistance("paxye", "pamne")); + assertEquals(-1, MathLesson10_DynamicProgramming.getStrDistance(null, null)); + } + + @Test + public void getLeastNotes() { + int[] values = {2, 3, 7}; + assertEquals(-1, MathLesson10_DynamicProgramming.getLeastNotes(null, 1)); + assertEquals(-1, MathLesson10_DynamicProgramming.getLeastNotes(new int[]{}, 7)); + assertEquals(0, MathLesson10_DynamicProgramming.getLeastNotes(values, 1)); + assertEquals(1, MathLesson10_DynamicProgramming.getLeastNotes(values, 2)); + assertEquals(1, MathLesson10_DynamicProgramming.getLeastNotes(values, 3)); + assertEquals(2, MathLesson10_DynamicProgramming.getLeastNotes(values, 6)); + assertEquals(1, MathLesson10_DynamicProgramming.getLeastNotes(values, 7)); + assertEquals(3, MathLesson10_DynamicProgramming.getLeastNotes(values, 8)); + assertEquals(2, MathLesson10_DynamicProgramming.getLeastNotes(values, 9)); + assertEquals(2, MathLesson10_DynamicProgramming.getLeastNotes(values, 10)); + } +} \ No newline at end of file diff --git a/src/test/java/geek/math/MathLesson12_TrieTest.java b/src/test/java/geek/math/MathLesson12_TrieTest.java new file mode 100644 index 0000000..a2d5f8f --- /dev/null +++ b/src/test/java/geek/math/MathLesson12_TrieTest.java @@ -0,0 +1,40 @@ +package geek.math; + +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.*; + +public class MathLesson12_TrieTest { + MathLesson12_Trie trie = new MathLesson12_Trie(); + + @Before + public void setUp() throws Exception { + trie.put("test", "this is a test"); + trie.put("taste", "the favour you got with your tone"); + trie.put("try", "give it a try"); + trie.put("trie", "it is pronounced as tree"); + trie.put("a", "one"); + trie.put("zebra", "a kind of horse with stripe"); + trie.put("tester", "the person does the test"); + trie.put("banana", "a kind of fruit"); + trie.put("church", "a place"); + trie.put("drive", "go forward by riding on something"); + trie.put("driver", "the person drives"); + trie.put("synchronisation", "sync"); + trie.put("atmosphericsurveillance", "atmospheric surveillance"); + System.out.println(trie.toString()); + System.out.println(trie.bfsTraverse().toString()); + } + + @Test + public void put() { + trie.put("my", "another form of me describing the belonging"); + assertNotNull(trie.find("my")); + } + + @Test + public void find() { + assertNotNull(trie.find("trie")); + } +} \ No newline at end of file diff --git a/src/test/java/geek/math/MathLesson14_GraphTest.java b/src/test/java/geek/math/MathLesson14_GraphTest.java new file mode 100644 index 0000000..2f1bca8 --- /dev/null +++ b/src/test/java/geek/math/MathLesson14_GraphTest.java @@ -0,0 +1,80 @@ +package geek.math; + +import org.junit.Before; +import org.junit.Test; + +import java.util.*; + +import static org.junit.Assert.*; + +public class MathLesson14_GraphTest { + + private MathLesson14_Graph userGraph; + + @Before + public void setUp() throws Exception { + userGraph = new MathLesson14_Graph(10); + userGraph.append(new Node(0, new int[]{1, 8})) + .append(new Node(1, new int[]{0, 6, 7, 9})) + .append(new Node(2, new int[]{4, 9})) + .append(new Node(3, new int[]{5})) + .append(new Node(4, new int[]{2, 6, 7})) + .append(new Node(5, new int[]{3})) + .append(new Node(6, new int[]{1, 4})) + .append(new Node(7, new int[]{1, 4, 8, 9})) + .append(new Node(8, new int[]{0, 7})) + .append(new Node(9, new int[]{1, 2, 7})); + System.out.println(userGraph.toString()); + } + + @Test + public void testBfs() { + List friendOfDegree = userGraph.bfs(0); + System.out.println("friend list of user 0: "); + friendOfDegree.forEach(d -> System.out.println(Arrays.deepToString(d))); + assertEquals(3, friendOfDegree.size()); + friendOfDegree = userGraph.bfs(3); + assertEquals(1, friendOfDegree.size()); + } + + @Test + public void randomBfs() { + MathLesson14_Graph r = new MathLesson14_Graph(); + System.out.println(r.toString()); + List f = r.bfs(1); + } + + @Test + public void distance() { + assertEquals(0, userGraph.distance(0, 0)); + assertEquals(1, userGraph.distance(0, 1)); + assertEquals(2, userGraph.distance(0, 6)); + assertEquals(3, userGraph.distance(0, 4)); + assertEquals(-1, userGraph.distance(0, 3)); + } + + public int lengthOfLongestSubstring(String s) { + if ( s == null || s.length() == 0) { + return 0; + } + int max = 0; + Set set = new HashSet<>(); + Queue queue = new LinkedList<>(); + char[] chars = s.toCharArray(); + for (int i = 0; i < chars.length; ++i) { + char c = chars[i]; + if (set.contains(c)) { + int count = queue.size(); + if (count > max) { + max = count; + } + while (queue.remove() != c) {} + queue.add(c); + } else { + set.add(c); + queue.add(c); + } + } + return Math.max(max, queue.size()); + } +} \ No newline at end of file diff --git a/src/test/java/geek/math/MathLesson15_DijkstraTest.java b/src/test/java/geek/math/MathLesson15_DijkstraTest.java new file mode 100644 index 0000000..2440ebf --- /dev/null +++ b/src/test/java/geek/math/MathLesson15_DijkstraTest.java @@ -0,0 +1,83 @@ +package geek.math; + +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; +import java.util.Map; + +import static org.junit.Assert.*; + +public class MathLesson15_DijkstraTest { + + MathLesson15_Dijkstra dijkstra; + + @Before + public void setUp() throws Exception { + dijkstra = new MathLesson15_Dijkstra(10); + /** + * append(new Node(0, new int[]{1, 8})) + * .append(new Node(1, new int[]{0, 6, 7, 9})) + * .append(new Node(2, new int[]{4, 9})) + * .append(new Node(3, new int[]{5})) + * .append(new Node(4, new int[]{2, 6, 7})) + * .append(new Node(5, new int[]{3})) + * .append(new Node(6, new int[]{1, 4})) + * .append(new Node(7, new int[]{1, 4, 8, 9})) + * .append(new Node(8, new int[]{0, 7})) + * .append(new Node(9, new int[]{1, 2, 7})); + */ + dijkstra.vertices[0] = DijkstraVertex.parse("0(1, 0.3)(8, 0.1)"); + dijkstra.vertices[1] = DijkstraVertex.parse("1(0, 0.2)(6, 0.4)(7, 0.3)(9, 0.1)"); + dijkstra.vertices[2] = DijkstraVertex.parse("2(4, 0.5)"); + dijkstra.vertices[3] = DijkstraVertex.parse("3(5, 1)"); + dijkstra.vertices[4] = DijkstraVertex.parse("4(2,0.4)(6,0.6)(7,0.3)"); + dijkstra.vertices[5] = DijkstraVertex.parse("5(3,1)"); + dijkstra.vertices[6] = DijkstraVertex.parse("6(4,0.3)"); + dijkstra.vertices[7] = DijkstraVertex.parse("7(1, 0.3)(4, 0.1)(8, 0.15)(9, 0.05)"); + dijkstra.vertices[8] = DijkstraVertex.parse("8(0, 0.1)(7, 0.15)"); + dijkstra.vertices[9] = DijkstraVertex.parse("9(1, 0.1)(2, 0.1)(7, 0.05)"); + } + + @Test + public void parse() { + DijkstraVertex v = new DijkstraVertex(0); + DijkstraVertex v1 = DijkstraVertex.parse("0"); + assertEquals(v, v1); + v.addConnection(1, 0.5); + DijkstraVertex v2 = DijkstraVertex.parse("0(1, 0.5)"); + assertEquals(v, v2); + DijkstraVertex v3 = DijkstraVertex.parse("0(1,0.5)(3,0.3)(9,0.2)(5,0.1)"); + Map newConnections = new HashMap<>(); + newConnections.put(1, 0.5); + newConnections.put(3, 0.3); + newConnections.put(9, 0.2); + newConnections.put(5, 0.1); + v.setConnections(newConnections); + assertEquals(v, v3); + } + + @Test + public void getBestPath() { + assertEquals(0.0, dijkstra.getBestPath(1, 1), 0.0001); + assertEquals(Double.NEGATIVE_INFINITY, dijkstra.getBestPath(0, 3), 0.0001); + assertEquals(Double.NEGATIVE_INFINITY, dijkstra.getBestPath(2, 5), 0.0001); + assertEquals(0.3, dijkstra.getBestPath(0, 1), 0.0001); + assertEquals(0.2, dijkstra.getBestPath(1, 0), 0.0001); + assertEquals(0.25, dijkstra.getBestPath(1, 4), 0.0001); + assertEquals(0.45, dijkstra.getBestPath(4, 1), 0.0001); + assertEquals(0.35, dijkstra.getBestPath(0, 4), 0.0001); + assertEquals(0.55, dijkstra.getBestPath(4, 0), 0.0001); + assertEquals(0.3, dijkstra.getBestPath(0, 9), 0.0001); + assertEquals(0.3, dijkstra.getBestPath(9, 0), 0.0001); + assertEquals(0.2, dijkstra.getBestPath(1, 2), 0.0001); + assertEquals(0.95, dijkstra.getBestPath(2, 1), 0.0001); + assertEquals(0.65, dijkstra.getBestPath(6, 9), 0.0001); + assertEquals(0.5, dijkstra.getBestPath(9, 6), 0.0001); + } + + @Test(expected = IllegalArgumentException.class) + public void invalidArguments() { + dijkstra.getBestPath(0, dijkstra.size); + } +} \ No newline at end of file