diff --git a/pom.xml b/pom.xml index b0cf76c..bfef018 100644 --- a/pom.xml +++ b/pom.xml @@ -20,9 +20,9 @@ 4.1.32.Final - org.junit.jupiter - junit-jupiter-engine - 5.6.2 + junit + junit + 4.13.2 test diff --git "a/src/main/java/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" "b/src/main/java/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" new file mode 100644 index 0000000..2de7f51 --- /dev/null +++ "b/src/main/java/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276.java" @@ -0,0 +1,35 @@ +package algorithm.array; + +/** + * @author Ethan Zhang + * @date 2022/4/21 + */ +public class 二分查找 { + + public static void main(String[] args) { + int[] array = new int[] {1, 2, 3, 4, 5, 6}; + + System.out.println(binarySearch(array, 1)); + } + + public static int binarySearch(int[] array, int target) { + if (array == null || array.length == 0) { + return -1; + } + + int left = 0; + int right = array.length - 1; + while (left <= right) { + int mid = (left + right) / 2; + if (array[mid] == target) { + return mid; + } else if (array[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return -1; + } +} diff --git "a/src/main/java/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276\345\267\246\350\276\271\347\225\214.java" "b/src/main/java/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276\345\267\246\350\276\271\347\225\214.java" new file mode 100644 index 0000000..f820f9d --- /dev/null +++ "b/src/main/java/algorithm/array/\344\272\214\345\210\206\346\237\245\346\211\276\345\267\246\350\276\271\347\225\214.java" @@ -0,0 +1,34 @@ +package algorithm.array; + +/** + * @author Ethan Zhang + * @date 2022/4/23 + */ +public class 二分查找左边界 { + + public static int leftBoundary(int[] array, int target) { + if (array == null || array.length == 0) { + return -1; + } + + int left = 0; + int right = array.length - 1; + while (left <= right) { + int mid = (left + right) / 2; + if (target < array[mid]) { + right = mid - 1; + } else if (target > array[mid]) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + // 检查target比数组所有元素都大的越界情况以及非越界情况但找不到target的情况 + if (left >= array.length || array[left] != target) { + return -1; + } + + return left; + } +} diff --git "a/src/main/java/algorithm/binary_tree/Morris\351\201\215\345\216\206.java" "b/src/main/java/algorithm/binary_tree/Morris\351\201\215\345\216\206.java" index ff791fd..e83beca 100644 --- "a/src/main/java/algorithm/binary_tree/Morris\351\201\215\345\216\206.java" +++ "b/src/main/java/algorithm/binary_tree/Morris\351\201\215\345\216\206.java" @@ -1,5 +1,6 @@ package algorithm.binary_tree; +import algorithm.data_structure.BinarySearchTree; import algorithm.data_structure.BinaryTree; import algorithm.utils.TreeNode; import com.google.common.collect.Lists; @@ -11,9 +12,11 @@ public class Morris遍历 { public static void main(String[] args) { - TreeNode root = BinaryTree.create(Lists.newArrayList(1, 2, 3, 4, 5, 6, 7)); + TreeNode head = BinarySearchTree.create(Lists.newArrayList(1, 2, 3, 4, 5, 6, 7)); - morrisTraverse(root); + morrisTraverse(head); + morrisTraverseToPreOrder(head); + morrisTraverseToInOrder(head); } public static void morrisTraverse(TreeNode head) { @@ -25,16 +28,18 @@ public static void morrisTraverse(TreeNode head) { TreeNode cur = head; while (cur != null) { mostRight = cur.left; - while (mostRight.right != null && mostRight.right != cur) { - mostRight = mostRight.right; - } + if (mostRight != null) { + while (mostRight.right != null && mostRight.right != cur) { + mostRight = mostRight.right; + } - if (mostRight.right == null) { - mostRight.right = cur; - cur = cur.left; - continue; - } else { - mostRight.right = null; + if (mostRight.right == null) { + mostRight.right = cur; + cur = cur.left; + continue; + } else { + mostRight.right = null; + } } cur = cur.right; diff --git "a/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\346\214\211Zigzag\346\211\223\345\215\260.java" "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\346\214\211Zigzag\346\211\223\345\215\260.java" new file mode 100644 index 0000000..6cdb7e5 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\346\214\211Zigzag\346\211\223\345\215\260.java" @@ -0,0 +1,77 @@ +package algorithm.binary_tree; + +import algorithm.data_structure.BinaryTree; +import algorithm.utils.TreeNode; +import com.google.common.collect.Lists; +import java.util.Deque; +import java.util.LinkedList; + +/** + * @author Ethan Zhang + * @date 2022/4/24 + */ +public class 二叉树按Zigzag打印 { + + public static void main(String[] args) { + TreeNode head = BinaryTree.create(Lists.newArrayList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); + + printByZigzag1(head); + } + + public static void printByZigzag1(TreeNode head) { + if (head == null) { + return; + } + + Deque deque = new LinkedList<>(); + deque.offerFirst(head); + + int level = 0; + boolean positive = true; + + printLevel(level++, positive); + + TreeNode last = head; + TreeNode nLast = null; + while (!deque.isEmpty()) { + if (positive) { + head = deque.pollFirst(); + if (head.left != null) { + nLast = nLast == null ? head.left : nLast; + deque.offerLast(head.left); + } + + if (head.right != null) { + nLast = nLast == null ? head.right : nLast; + deque.offerLast(head.right); + } + } else { + head = deque.pollLast(); + if (head.right != null) { + nLast = nLast == null ? head.right : nLast; + deque.offerFirst(head.right); + } + + if (head.left != null) { + nLast = nLast == null ? head.left : nLast; + deque.offerFirst(head.left); + } + } + + System.out.print(head.value + " "); + if (last == head && !deque.isEmpty()) { + last = nLast; + nLast = null; + positive = !positive; + + System.out.println(); + printLevel(level++, positive); + } + } + } + + public static void printLevel(int level, boolean positive) { + System.out.print("Level " + level + " from "); + System.out.print(positive ? "left to right:" : "right to left"); + } +} diff --git "a/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.java" "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.java" new file mode 100644 index 0000000..41e31d5 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\347\232\204\345\272\217\345\210\227\345\214\226\345\222\214\345\217\215\345\272\217\345\210\227\345\214\226.java" @@ -0,0 +1,161 @@ +package algorithm.binary_tree; + +import algorithm.data_structure.BinaryTree; +import algorithm.utils.TreeNode; +import com.google.common.collect.Lists; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + +/** + * @author Ethan Zhang + * @date 2022/4/27 + */ +public class 二叉树的序列化和反序列化 { + + private static final String EMPTY_VALUE = "#"; + + public static void main(String[] args) { + TreeNode head = BinaryTree.create(Lists.newArrayList(1, 2, 3, 4, 5, 6)); + + System.out.println(preSerialize(head)); + System.out.println(preSerialize1(head)); + } + + + public static String preSerialize(TreeNode head) { + // 先序遍历序列化 + if (head == null) { + return ""; + } + + Stack stack = new Stack<>(); + stack.push(head); + + StringBuilder builder = new StringBuilder(); + while (!stack.isEmpty()) { + TreeNode cur = stack.pop(); + + if (cur == null) { + builder.append("#!"); + } else { + builder.append(cur.value) + .append("!"); + } + + if (cur != null) { + stack.push(cur.right); + stack.push(cur.left); + } + } + + return builder.toString(); + } + + public static String preSerialize1(TreeNode head) { + // 先序遍历序列化 + if (head == null) { + return "#!"; + } + + String result = head.value + "!"; + result += preSerialize1(head.left); + result += preSerialize1(head.right); + + return result; + } + + public static TreeNode preDeserialize(String str) { + if (str == null || str.length() == 0) { + return null; + } + + String[] segments = str.split("!"); + Queue queue = new LinkedList<>(); + for (String segment : segments) { + queue.offer(segment); + } + + return preDeserializeRecursive(queue); + } + + private static TreeNode preDeserializeRecursive(Queue queue) { + String value = queue.poll(); + if (EMPTY_VALUE.equals(value)) { + return null; + } + + TreeNode head = new TreeNode(Integer.parseInt(value)); + head.left = preDeserializeRecursive(queue); + head.right = preDeserializeRecursive(queue); + + return head; + } + + public static String serializeByLevel(TreeNode head) { + if (head == null) { + return EMPTY_VALUE; + } + + String res = head.value + "!"; + + Queue queue = new LinkedList<>(); + queue.offer(head); + + while (!queue.isEmpty()) { + head = queue.poll(); + if (head.left != null) { + res += head.left.value + "!"; + queue.offer(head.left); + } else { + res += EMPTY_VALUE; + } + + if (head.right != null) { + res += head.right.value + "!"; + queue.offer(head.right); + } else { + res += EMPTY_VALUE; + } + } + + return res; + } + + public static TreeNode deserializeByLevel(String str) { + String[] segments = str.split("!"); + + int index = 0; + + TreeNode head = generateNode(segments[index++]); + + Queue queue = new LinkedList<>(); + if (head != null) { + queue.offer(head); + } + + while (!queue.isEmpty()) { + TreeNode cur = queue.poll(); + cur.left = generateNode(segments[index++]); + cur.right = generateNode(segments[index++]); + + if (cur.left != null) { + queue.offer(cur.left); + } + + if (cur.right != null) { + queue.offer(cur.right); + } + } + + return head; + } + + private static TreeNode generateNode(String segment) { + if (segment.equals("#")) { + return null; + } + + return new TreeNode(Integer.parseInt(segment)); + } +} diff --git "a/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\347\232\204\346\214\211\345\261\202\346\211\223\345\215\260.java" "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\347\232\204\346\214\211\345\261\202\346\211\223\345\215\260.java" new file mode 100644 index 0000000..43fe260 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\347\232\204\346\214\211\345\261\202\346\211\223\345\215\260.java" @@ -0,0 +1,58 @@ +package algorithm.binary_tree; + +import algorithm.data_structure.BinaryTree; +import algorithm.utils.TreeNode; +import com.google.common.collect.Lists; +import java.util.Deque; +import java.util.LinkedList; + +/** + * @author Ethan Zhang + * @date 2022/4/24 + */ +public class 二叉树的按层打印 { + + public static void main(String[] args) { + TreeNode head = BinaryTree.create(Lists.newArrayList(1, 2, 3, 4, 5, 6, 7)); + + printByLevel(head); + } + + public static void printByLevel(TreeNode head) { + if (head == null) { + return; + } + + Deque queue = new LinkedList<>(); + queue.offer(head); + + int level = 1; + + System.out.print(String.format("Level %d:", level++)); + + TreeNode last = head; + TreeNode nLast = null; + while (!queue.isEmpty()) { + TreeNode cur = queue.poll(); + + System.out.print(cur.value); + + if (cur.left != null) { + nLast = cur.left; + queue.offer(cur.left); + } + + if (cur.right != null) { + nLast = cur.right; + queue.offer(cur.right); + } + + // 最后一行就不打印了 + if (last == cur && !queue.isEmpty()) { + last = nLast; + + System.out.print(String.format("\nLevel %d:", level++)); + } + } + } +} diff --git "a/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\350\212\202\347\202\271\351\227\264\347\232\204\346\234\200\345\244\247\350\267\235\347\246\273\351\227\256\351\242\230.java" "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\350\212\202\347\202\271\351\227\264\347\232\204\346\234\200\345\244\247\350\267\235\347\246\273\351\227\256\351\242\230.java" new file mode 100644 index 0000000..b26176a --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\344\272\214\345\217\211\346\240\221\350\212\202\347\202\271\351\227\264\347\232\204\346\234\200\345\244\247\350\267\235\347\246\273\351\227\256\351\242\230.java" @@ -0,0 +1,43 @@ +package algorithm.binary_tree; + +import algorithm.utils.TreeNode; + +/** + * @author Ethan Zhang + * @date 2022/5/18 + */ +public class 二叉树节点间的最大距离问题 { + + public static void main(String[] args) { + + } + + public int maxDistance(TreeNode head) { + return maxDistanceRecursive(head).maxDistance; + } + + public ReturnType maxDistanceRecursive(TreeNode head) { + if (head == null) { + return new ReturnType(0, 0); + } + + ReturnType left = maxDistanceRecursive(head.left); + ReturnType right = maxDistanceRecursive(head.right); + + int height = Math.max(left.height, right.height) + 1; + int maxDistance = Math.max(left.height + right.height + 1, Math.max(left.maxDistance, right.maxDistance)); + + return new ReturnType(maxDistance, height); + } + + private static class ReturnType { + private final int maxDistance; + + private final int height; + + public ReturnType(int maxDistance, int height) { + this.maxDistance = maxDistance; + this.height = height; + } + } +} diff --git "a/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255t1\346\240\221\344\270\255\346\230\257\345\220\246\346\234\211\344\270\216t2\346\240\221\346\213\223\346\211\221\347\273\223\346\236\204\345\256\214\345\205\250\347\233\270\345\220\214\347\232\204\345\255\220\346\240\221.java" "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255t1\346\240\221\344\270\255\346\230\257\345\220\246\346\234\211\344\270\216t2\346\240\221\346\213\223\346\211\221\347\273\223\346\236\204\345\256\214\345\205\250\347\233\270\345\220\214\347\232\204\345\255\220\346\240\221.java" new file mode 100644 index 0000000..135629e --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255t1\346\240\221\344\270\255\346\230\257\345\220\246\346\234\211\344\270\216t2\346\240\221\346\213\223\346\211\221\347\273\223\346\236\204\345\256\214\345\205\250\347\233\270\345\220\214\347\232\204\345\255\220\346\240\221.java" @@ -0,0 +1,80 @@ +package algorithm.binary_tree; + +import algorithm.utils.TreeNode; + +/** + * @author Ethan Zhang + * @date 2022/5/3 + */ +public class 判断t1树中是否有与t2树拓扑结构完全相同的子树 { + + public static boolean contains(TreeNode t1, TreeNode t2) { + String str1 = serializeByPre(t1); + String str2 = serializeByPre(t2); + + return kmp(str1, str2) != -1; + } + + private static int kmp(String str1, String str2) { + if (str1 == null || str2 == null || str2.length() < 1 || str1.length() < str2.length()) { + return -1; + } + + int s1 = 0; + int s2 = 0; + char[] ss = str1.toCharArray(); + char[] tt = str2.toCharArray(); + int[] next = getNextArray(ss); + while (s1 < ss.length && s2 < tt.length) { + if (ss[s1] == tt[s2]) { + s1++; + s2++; + } else if (next[s2] == -1) { + // 第一位就不想等的情况 + s1++; + } else { + s2 = next[s2]; + } + } + + return s2 == tt.length ? s2 - s1 : -1; + } + + private static int[] getNextArray(char[] ss) { + if (ss.length == 1) { + return new int[]{-1}; + } + + int[] res = new int[ss.length]; + res[0] = -1; + res[1] = 0; + + int cnt = 0; + int pos = 2; + while (pos < ss.length) { + if (ss[cnt] == ss[pos]) { + res[pos++] = ++cnt; + // TODO + } else if (cnt > 0) { + // 不想等但是有共同前缀,退到相同前缀部分的下一位继续比较,如果一直都不匹配,最终会退到cnt=0 + cnt = res[cnt]; + } else { + res[pos++] = 0; + } + } + + return new int[0]; + } + + private static String serializeByPre(TreeNode head) { + if (head == null) { + return "#!"; + } + + String res = head.value + "!"; + res += serializeByPre(head.left); + res += serializeByPre(head.right); + + return res; + } +} diff --git "a/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255t1\346\240\221\346\230\257\345\220\246\345\214\205\345\220\253t2\346\240\221\347\232\204\345\205\250\351\203\250\346\213\223\346\211\221\347\273\223\346\236\204.java" "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255t1\346\240\221\346\230\257\345\220\246\345\214\205\345\220\253t2\346\240\221\347\232\204\345\205\250\351\203\250\346\213\223\346\211\221\347\273\223\346\236\204.java" new file mode 100644 index 0000000..2b4fffa --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255t1\346\240\221\346\230\257\345\220\246\345\214\205\345\220\253t2\346\240\221\347\232\204\345\205\250\351\203\250\346\213\223\346\211\221\347\273\223\346\236\204.java" @@ -0,0 +1,44 @@ +package algorithm.binary_tree; + +import algorithm.data_structure.BinaryTree; +import algorithm.utils.TreeNode; + +/** + * @author Ethan Zhang + * @date 2022/4/26 + */ +public class 判断t1树是否包含t2树的全部拓扑结构 { + + public static void main(String[] args) { + final TreeNode t1 = BinaryTree.create(1, 2, 3, 4, 5, 6, 7, 8); + final TreeNode t2 = BinaryTree.create(3, 4, 5, 8); + final TreeNode t3 = BinaryTree.create(2, 4, 5, 8); + + System.out.println(contains(t1, t2)); + System.out.println(contains(t1, t3)); + } + + public static boolean contains(TreeNode t1, TreeNode t2) { + if (t2 == null) { + return true; + } + + if (t1 == null) { + return false; + } + + return containsRecursive(t1, t2) || contains(t1.left, t2) || contains(t1.right, t2); + } + + private static boolean containsRecursive(TreeNode t1, TreeNode t2) { + if (t2 == null) { + return true; + } + + if (t1 == null || t1.value != t2.value) { + return false; + } + + return containsRecursive(t1.left, t2.left) && containsRecursive(t1.right, t2.right); + } +} diff --git "a/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255\344\270\200\351\242\227\344\272\214\345\217\211\346\240\221\346\230\257\345\220\246\344\270\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\345\222\214\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221.java" "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255\344\270\200\351\242\227\344\272\214\345\217\211\346\240\221\346\230\257\345\220\246\344\270\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\345\222\214\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..978fb35 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255\344\270\200\351\242\227\344\272\214\345\217\211\346\240\221\346\230\257\345\220\246\344\270\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\345\222\214\345\256\214\345\205\250\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,91 @@ +package algorithm.binary_tree; + +import algorithm.data_structure.BinarySearchTree; +import algorithm.data_structure.BinaryTree; +import algorithm.utils.TreeNode; +import com.google.common.collect.Lists; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author Ethan Zhang + * @date 2022/5/5 + */ +public class 判断一颗二叉树是否为搜索二叉树和完全二叉树 { + + public static void main(String[] args) { + TreeNode head = BinarySearchTree.create(Lists.newArrayList(1, 2, 3, 4, 5, 6, 7)); + + System.out.println(isBST(head)); + + head = BinaryTree.create(Lists.newArrayList(1, 3, 2, 4, 0, 6, 7)); + + System.out.println(isBST(head)); + } + + public static boolean isBST(TreeNode head) { + if (head == null) { + return true; + } + + boolean result = true; + TreeNode pre = null; + TreeNode mostRight = null; + while (head != null) { + mostRight = head.left; + if (mostRight != null) { + while (mostRight.right != null && mostRight.right != head) { + mostRight = mostRight.right; + } + + if (mostRight.right == null) { + mostRight.right = head; + head = head.left; + continue; + } else { + mostRight.right = null; + } + } + + if (pre != null && pre.value > head.value) { + result = false; + } + + pre = head; + head = head.right; + } + + return result; + } + + public static boolean isCST(TreeNode head) { + if (head == null) { + return true; + } + + boolean leaf = false; + Queue queue = new LinkedList<>(); + queue.offer(head); + while (!queue.isEmpty()) { + head = queue.poll(); + + TreeNode left = head.left; + TreeNode right = head.right; + if ((leaf && (left != null || right != null)) || (left == null && right != null)) { + return false; + } + + if (left != null) { + queue.offer(left); + } + + if (right != null) { + queue.offer(right); + } else { + leaf = true; + } + } + + return true; + } +} diff --git "a/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255\344\272\214\345\217\211\346\240\221\346\230\257\345\220\246\344\270\272\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255\344\272\214\345\217\211\346\240\221\346\230\257\345\220\246\344\270\272\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..ccd0852 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\345\210\244\346\226\255\344\272\214\345\217\211\346\240\221\346\230\257\345\220\246\344\270\272\345\271\263\350\241\241\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,41 @@ +package algorithm.binary_tree; + +import algorithm.utils.TreeNode; + +/** + * @author Ethan Zhang + * @date 2022/5/4 + */ +public class 判断二叉树是否为平衡二叉树 { + + public static boolean isBalanced(TreeNode head) { + return process(head).isBalanced; + } + + private static ReturnType process(TreeNode head) { + if (head == null) { + return new ReturnType(true, 0); + } + + ReturnType left = process(head.left); + ReturnType right = process(head.right); + + int height = Math.max(left.height, right.height) + 1; + + boolean balanced = left.isBalanced && right.isBalanced && Math.abs(left.height - right.height) < 2; + + return new ReturnType(balanced, height); + } + + + private static class ReturnType { + public boolean isBalanced; + + public int height; + + public ReturnType(boolean isBalanced, int height) { + this.isBalanced = isBalanced; + this.height = height; + } + } +} diff --git "a/src/main/java/algorithm/binary_tree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\346\211\276\345\210\260\344\270\244\344\270\252\350\212\202\347\202\271\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" "b/src/main/java/algorithm/binary_tree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\346\211\276\345\210\260\344\270\244\344\270\252\350\212\202\347\202\271\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" new file mode 100644 index 0000000..b33f8a8 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\345\234\250\344\272\214\345\217\211\346\240\221\344\270\255\346\211\276\345\210\260\344\270\244\344\270\252\350\212\202\347\202\271\347\232\204\346\234\200\350\277\221\345\205\254\345\205\261\347\245\226\345\205\210.java" @@ -0,0 +1,91 @@ +package algorithm.binary_tree; + +import algorithm.data_structure.BinaryTree; +import algorithm.utils.TreeNode; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.springframework.util.Assert; + +/** + * @author Ethan Zhang + * @date 2022/5/9 + */ +public class 在二叉树中找到两个节点的最近公共祖先 { + + public static void main(String[] args) { + TreeNode head = BinaryTree.create(1, 2, 3, 4, 5, 6, 7); + + TreeNode parent = findParent1(head, new TreeNode(2), new TreeNode(4)); + + Assert.isTrue(parent.equals(new TreeNode(2))); + + parent = findParent1(head, new TreeNode(2), new TreeNode(7)); + + Assert.isTrue(parent.equals(new TreeNode(1))); + } + + public static TreeNode findParent(TreeNode head, TreeNode o1, TreeNode o2) { + if (head == null || head == o1 || head == o2) { + return head; + } + + TreeNode left = findParent(head.left, o1, o2); + TreeNode right = findParent(head.right, o1, o2); + if (left != null && right != null) { + return head; + } + + return left != null ? left : right; + } + + public static TreeNode findParent1(TreeNode head, TreeNode o1, TreeNode o2) { + ParentFinder finder = new ParentFinder(head); + return finder.find(o1, o2); + } + + private static class ParentFinder { + private Map cache; + + public ParentFinder(TreeNode head) { + this.cache = new HashMap<>(); + if (head != null) { + this.cache.put(head, null); + } + + setMap(head); + } + + private void setMap(TreeNode head) { + if (head == null) { + return; + } + + if (head.left != null) { + this.cache.put(head.left, head); + } + + if (head.right != null) { + this.cache.put(head.right, head); + } + + setMap(head.left); + setMap(head.right); + } + + public TreeNode find(TreeNode o1, TreeNode o2) { + Set path = new HashSet<>(); + while (this.cache.containsKey(o1)) { + path.add(o1); + o1 = this.cache.get(o1); + } + + while (!path.contains(o2)) { + o2 = this.cache.get(o2); + } + + return o2; + } + } +} diff --git "a/src/main/java/algorithm/binary_tree/\346\211\276\345\210\260\344\272\214\345\217\211\346\240\221\344\270\255\347\254\246\345\220\210\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\346\235\241\344\273\266\347\232\204\346\234\200\345\244\247\346\213\223\346\211\221\347\273\223\346\236\204.java" "b/src/main/java/algorithm/binary_tree/\346\211\276\345\210\260\344\272\214\345\217\211\346\240\221\344\270\255\347\254\246\345\220\210\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\346\235\241\344\273\266\347\232\204\346\234\200\345\244\247\346\213\223\346\211\221\347\273\223\346\236\204.java" new file mode 100644 index 0000000..fe33096 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\346\211\276\345\210\260\344\272\214\345\217\211\346\240\221\344\270\255\347\254\246\345\220\210\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\346\235\241\344\273\266\347\232\204\346\234\200\345\244\247\346\213\223\346\211\221\347\273\223\346\236\204.java" @@ -0,0 +1,113 @@ +package algorithm.binary_tree; + +import algorithm.utils.TreeNode; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.StringUtils; + +/** + * @author Ethan Zhang + * @date 2022/4/19 + */ +public class 找到二叉树中符合搜索二叉树条件的最大拓扑结构 { + + public static void main(String[] args) { + String[] strs = StringUtils.split("[UG1, UG2, UG3]", "[] ,"); + + System.out.println(Arrays.toString(strs)); + } + + public int bstTopoSize1(TreeNode head) { + if (head == null) { + return 0; + } + + int maxTopoSize = maxTopo(head, head); + maxTopoSize = Math.max(bstTopoSize1(head.left), maxTopoSize); + maxTopoSize = Math.max(bstTopoSize1(head.right), maxTopoSize); + + return maxTopoSize; + } + + private int maxTopo(TreeNode h, TreeNode n) { + if (h != null && n != null && isBSTNode(h, n, n.value)) { + return maxTopo(h, n.left) + maxTopo(h, n.right) + 1; + } + + return 0; + } + + private boolean isBSTNode(TreeNode h, TreeNode n, int value) { + if (h == null) { + return false; + } + + if (h == n) { + return true; + } + + return isBSTNode(value > h.value ? h.right : h.left, n, value); + } + + public int bstTopoSize2(TreeNode head) { + Map cache = new HashMap<>(); + + return postOrder(head, cache); + } + + private int postOrder(TreeNode head, Map cache) { + if (head == null) { + return 0; + } + + int left = postOrder(head.left, cache); + int right = postOrder(head.right, cache); + + modifyMap(head.left, head.value, cache, true); + modifyMap(head.right, head.value, cache, false); + + Record lr = cache.get(head.left); + Record rr = cache.get(head.right); + + int lbst = lr == null ? 0 : lr.leftCnt + lr.rightCnt + 1; + int rbst = rr == null ? 0 : rr.leftCnt + rr.rightCnt + 1; + cache.put(head, new Record(lbst, rbst)); + + return Math.max(lbst + rbst + 1, Math.max(left, right)); + } + + private int modifyMap(TreeNode n, int v, Map cache, boolean s) { + if (n == null || (!cache.containsKey(n))) { + return 0; + } + + Record r = cache.get(n); + if ((s && n.value > v) || (!(s) && n.value < v)) { + cache.remove(n); + return r.leftCnt + r.rightCnt + 1; + } else { + int minus = modifyMap(s ? n.right : n.left, v, cache, s); + if (s) { + r.rightCnt = r.rightCnt - minus; + } else { + r.leftCnt = r.leftCnt - minus; + } + + cache.put(n, r); + + return minus; + } + } + + private static class Record { + public int leftCnt; + + public int rightCnt; + + private Record(int leftCnt, int rightCnt) { + this.leftCnt = leftCnt; + this.rightCnt = rightCnt; + } + } +} diff --git "a/src/main/java/algorithm/binary_tree/\346\240\271\346\215\256\345\220\216\345\272\217\346\225\260\347\273\204\351\207\215\345\273\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.java" "b/src/main/java/algorithm/binary_tree/\346\240\271\346\215\256\345\220\216\345\272\217\346\225\260\347\273\204\351\207\215\345\273\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..83cfd43 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\346\240\271\346\215\256\345\220\216\345\272\217\346\225\260\347\273\204\351\207\215\345\273\272\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,59 @@ +package algorithm.binary_tree; + +import algorithm.utils.TreeNode; +import org.springframework.util.Assert; + +/** + * @author Ethan Zhang + * @date 2022/5/4 + */ +public class 根据后序数组重建搜索二叉树 { + + public static void main(String[] args) { + int[] post = new int[]{1, 3, 2, 5, 7, 6, 4}; + + TreeNode head = restoreByPost(post); + + Assert.isTrue(head.value == 4); + Assert.isTrue(head.left.value == 2); + Assert.isTrue(head.right.value == 6); + + head = restoreByPost(new int[0]); + + Assert.isTrue(head == null); + } + + public static TreeNode restoreByPost(int[] array) { + if (array == null || array.length == 0) { + return null; + } + + return restoreByPostRecursively(array, 0, array.length - 1); + } + + private static TreeNode restoreByPostRecursively(int[] array, int start, int end) { + if (start > end) { + return null; + } + + int less = start; + int more = end; + for (int i = start; i < end; i++) { + if (array[end] > array[i]) { + less = i; + } else { + more = more == end ? end - 1 : i; + } + } + + TreeNode head = new TreeNode(array[end]); + if (more == less) { + return head; + } + + head.left = restoreByPostRecursively(array, start, less); + head.right = restoreByPostRecursively(array, more, end - 1); + + return head; + } +} diff --git "a/src/main/java/algorithm/binary_tree/\350\260\203\346\225\264\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\344\270\255\344\270\244\344\270\252\351\224\231\350\257\257\347\232\204\350\212\202\347\202\271.java" "b/src/main/java/algorithm/binary_tree/\350\260\203\346\225\264\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\344\270\255\344\270\244\344\270\252\351\224\231\350\257\257\347\232\204\350\212\202\347\202\271.java" new file mode 100644 index 0000000..52465d2 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\350\260\203\346\225\264\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221\344\270\255\344\270\244\344\270\252\351\224\231\350\257\257\347\232\204\350\212\202\347\202\271.java" @@ -0,0 +1,60 @@ +package algorithm.binary_tree; + +import algorithm.data_structure.BinarySearchTree; +import algorithm.utils.TreeNode; +import java.util.Arrays; +import java.util.Stack; + +/** + * @author Ethan Zhang + * @date 2022/4/26 + */ +public class 调整搜索二叉树中两个错误的节点 { + + public static void main(String[] args) { + TreeNode head = BinarySearchTree.create(5, 6, 3, 2, 1, 4, 9, 7, 8); + head.left.left.left.value = 9; + head.right.right.value = 1; + + System.out.println(Arrays.toString(correct(head))); + + head = BinarySearchTree.create(5, 6, 3, 2, 1, 4, 9, 7, 8); + head.left.left.value = 4; + head.left.right.value = 2; + + System.out.println(Arrays.toString(correct(head))); + } + + public static Integer[] correct(TreeNode head) { + if (head == null) { + return null; + } + + return inOrder(head); + } + + public static Integer[] inOrder(TreeNode head) { + TreeNode pre = null; + Integer[] result = new Integer[2]; + Stack stack = new Stack<>(); + while (!stack.isEmpty() || head != null) { + if (head != null) { + stack.push(head); + head = head.left; + } else { + head = stack.pop(); + + if (pre != null && pre.value > head.value) { + // 考虑两个错误的数字挨着的情况 + result[0] = result[0] == null ? pre.value : result[0]; + result[1] = head.value; + } + + pre = head; + head = head.right; + } + } + + return result; + } +} diff --git "a/src/main/java/algorithm/binary_tree/\351\200\232\350\277\207\346\234\211\345\272\217\346\225\260\347\273\204\347\224\237\346\210\220\345\271\263\350\241\241\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.java" "b/src/main/java/algorithm/binary_tree/\351\200\232\350\277\207\346\234\211\345\272\217\346\225\260\347\273\204\347\224\237\346\210\220\345\271\263\350\241\241\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.java" new file mode 100644 index 0000000..d192904 --- /dev/null +++ "b/src/main/java/algorithm/binary_tree/\351\200\232\350\277\207\346\234\211\345\272\217\346\225\260\347\273\204\347\224\237\346\210\220\345\271\263\350\241\241\346\220\234\347\264\242\344\272\214\345\217\211\346\240\221.java" @@ -0,0 +1,31 @@ +package algorithm.binary_tree; + +import algorithm.utils.TreeNode; + +/** + * @author Ethan Zhang + * @date 2022/5/6 + */ +public class 通过有序数组生成平衡搜索二叉树 { + + public static TreeNode generateBST(int[] sortedArray) { + if (sortedArray == null || sortedArray.length == 0) { + return null; + } + + return generateBSTRecursive(sortedArray, 0, sortedArray.length - 1); + } + + private static TreeNode generateBSTRecursive(int[] sortedArray, int start, int end) { + if (start > end) { + return null; + } + + int mid = (start + end) / 2; + TreeNode head = new TreeNode(sortedArray[mid]); + head.left = generateBSTRecursive(sortedArray, 0, mid - 1); + head.right = generateBSTRecursive(sortedArray, mid + 1, end); + + return head; + } +} diff --git a/src/main/java/algorithm/data_structure/SortedBinaryTree.java b/src/main/java/algorithm/data_structure/BinarySearchTree.java similarity index 78% rename from src/main/java/algorithm/data_structure/SortedBinaryTree.java rename to src/main/java/algorithm/data_structure/BinarySearchTree.java index 3c07f60..f9eab5b 100644 --- a/src/main/java/algorithm/data_structure/SortedBinaryTree.java +++ b/src/main/java/algorithm/data_structure/BinarySearchTree.java @@ -1,13 +1,15 @@ package algorithm.data_structure; import algorithm.utils.TreeNode; +import com.google.common.base.Preconditions; +import com.google.common.collect.Lists; import java.util.List; /** * @author Ethan Zhang * @date 2022/4/12 */ -public class SortedBinaryTree { +public class BinarySearchTree { private TreeNode root; @@ -48,11 +50,9 @@ private boolean containsRecursive(TreeNode current, int value) { } public static TreeNode create(List values) { - if (values == null || values.isEmpty()) { - return null; - } + Preconditions.checkNotNull(values); - SortedBinaryTree binaryTree = new SortedBinaryTree(); + BinarySearchTree binaryTree = new BinarySearchTree(); for (Integer value : values) { binaryTree.add(value); } @@ -60,6 +60,12 @@ public static TreeNode create(List values) { return binaryTree.root; } + public static TreeNode create(Integer... values) { + Preconditions.checkNotNull(values); + + return create(Lists.newArrayList(values)); + } + public TreeNode getRoot() { return root; } diff --git a/src/main/java/algorithm/data_structure/BinaryTree.java b/src/main/java/algorithm/data_structure/BinaryTree.java index 90dbeb9..be4db70 100644 --- a/src/main/java/algorithm/data_structure/BinaryTree.java +++ b/src/main/java/algorithm/data_structure/BinaryTree.java @@ -1,6 +1,7 @@ package algorithm.data_structure; import algorithm.utils.TreeNode; +import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import java.util.List; @@ -27,10 +28,17 @@ private static TreeNode createRecursive(List nums, TreeNode cur, int i) } public static TreeNode create(List nums) { + Preconditions.checkNotNull(nums); + BinaryTree binaryTree = new BinaryTree(); binaryTree.root = createRecursive(nums, binaryTree.root, 0); return binaryTree.root; } + public static TreeNode create(Integer... nums) { + Preconditions.checkNotNull(nums); + + return create(Lists.newArrayList(nums)); + } } diff --git "a/src/main/java/algorithm/link/\344\270\244\344\270\252\351\223\276\350\241\250\347\233\270\345\212\240.java" "b/src/main/java/algorithm/link/\344\270\244\344\270\252\351\223\276\350\241\250\347\233\270\345\212\240.java" new file mode 100644 index 0000000..12f937f --- /dev/null +++ "b/src/main/java/algorithm/link/\344\270\244\344\270\252\351\223\276\350\241\250\347\233\270\345\212\240.java" @@ -0,0 +1,48 @@ +package algorithm.link; + +import algorithm.utils.Node; +import java.util.LinkedList; +import java.util.Queue; + +/** + * @author Ethan Zhang + * @date 2022/5/6 + */ +public class 两个链表相加 { + + public Node add(Node head1, Node head2) { + if (head1 == null) { + return head2; + } + + if (head2 == null) { + return head1; + } + + int adder = 0; + Node dummy = new Node(0); + Node head = dummy; + while (head1 != null || head2 != null || adder != 0) { + int val1 = head1 == null ? 0 : head1.value; + int val2 = head2 == null ? 0 : head2.value; + + int sum = val1 + val2 + adder; + head.next = new Node(sum % 10); + head = head.next; + + adder = sum / 10; + + if (head1 != null) { + head1 = head1.next; + } + + if (head2 != null) { + head2 = head2.next; + } + } + + return dummy.next; + } + + +} diff --git "a/src/main/java/algorithm/link/\350\277\224\345\233\236\351\223\276\350\241\250\347\254\254K\344\270\252\350\212\202\347\202\271.java" "b/src/main/java/algorithm/link/\350\277\224\345\233\236\351\223\276\350\241\250\347\254\254K\344\270\252\350\212\202\347\202\271.java" new file mode 100644 index 0000000..372b142 --- /dev/null +++ "b/src/main/java/algorithm/link/\350\277\224\345\233\236\351\223\276\350\241\250\347\254\254K\344\270\252\350\212\202\347\202\271.java" @@ -0,0 +1,30 @@ +package algorithm.link; + +import algorithm.utils.Node; + +/** + * @author Ethan Zhang + * @date 2022/5/6 + */ +public class 返回链表第K个节点 { + + public static Node k(Node head, int k) { + if (head == null || k < 1) { + return null; + } + + Node slow, fast; + slow = fast = head; + while (k > 0) { + k--; + fast = fast.next; + } + + while (fast != null) { + slow = slow.next; + fast = fast.next; + } + + return slow; + } +} diff --git a/src/main/java/algorithm/utils/TreeNode.java b/src/main/java/algorithm/utils/TreeNode.java index 422c10a..9175f42 100644 --- a/src/main/java/algorithm/utils/TreeNode.java +++ b/src/main/java/algorithm/utils/TreeNode.java @@ -22,6 +22,25 @@ public TreeNode(int value, TreeNode left, TreeNode right) { this.right = right; } + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + TreeNode treeNode = (TreeNode) o; + + return value == treeNode.value; + } + + @Override + public int hashCode() { + return value; + } + public int getValue() { return value; }