diff --git a/note/0107/README.md b/note/0107/README.md index a8600d7c..dca179fb 100644 --- a/note/0107/README.md +++ b/note/0107/README.md @@ -31,7 +31,8 @@ return its bottom-up level order traversal as: ## 思路 0 -题意是从下往上按层遍历二叉树,每一层是从左到右,按层遍历,很明显,宽搜第一时间符合,因为是从下往上,所以插入的时候每次插到链表头即可。 +题意是从下往上按层遍历二叉树,每一层是从左到右,按层遍历,很明显,宽搜第一时间符合 +因为是从下往上,所以插入的时候每次插到链表头即可。 ```java /** diff --git a/progress.txt b/progress.txt new file mode 100644 index 00000000..5deb359a --- /dev/null +++ b/progress.txt @@ -0,0 +1,28 @@ +easy : +列表操作 21 83 104 + +medium: + +hard: + +可以分为基础的数据结构,比如数组、链表、栈、队列、二叉树、堆的使用 +这几种常见的数据结构的基础操作一定要很熟悉, +比如链表逆置、删除、获取第 K 个元素、判断是否有环等, +二叉树翻转、深度遍历、层级遍历、求树深度、公共父节点等。 + +已完成: 链表逆置, 删除, 获取第 K 个元素, 是否有环 +深度遍历, 求树深度, + +未完成:二叉树翻转 + +算法是一定要复习的,在很多面试的过程中都会穿插算法题。面试的算法题一般不会很难,可以分为基础的数据结构 +比如数组、链表、栈、队列、二叉树、堆的使用,这几种常见的数据结构的基础操作一定要很熟悉 +比如链表逆置、删除、获取第 K 个元素、判断是否有环等,二叉树翻转、深度遍历、层级遍历、求树深度、公共父节点等。 + + +另一种是常见的搜索、排序算法,这两类算法出现频率很高,一定要知道它们常见的几种实现方式,比如排序方式有 +冒泡、快排、插入、归并、堆排序等。注意这里一定不要简单地去记忆算法实现,因为面试的时候可能不会直接 +让你写出对应的算法,会出一些使用搜索或者排序算法来实现的题目, +这类题目你可以去 LeetCode 上通过标签过滤出来。 + + diff --git a/src/com/blankj/easy/_0021/Solution.java b/src/com/blankj/easy/_0021/Solution.java index aa92b142..7693aba7 100644 --- a/src/com/blankj/easy/_0021/Solution.java +++ b/src/com/blankj/easy/_0021/Solution.java @@ -1,6 +1,9 @@ package com.blankj.easy._021; import com.blankj.structure.ListNode; +import com.blankj.structure.ListNodeMe; + +import static java.lang.System.out; /** *
@@ -28,7 +31,7 @@ public ListNode mergeTwoLists(ListNode l1, ListNode l2) { return head.next; } - public static void main(String[] args) { + public static void main2(String[] args) { Solution solution = new Solution(); ListNode listNode0 = ListNode.createTestData("[1,3,5,7,9]"); ListNode listNode1 = ListNode.createTestData("[2,4,6,8,10]"); @@ -36,4 +39,30 @@ public static void main(String[] args) { ListNode.print(listNode1); ListNode.print(solution.mergeTwoLists(listNode0, listNode1)); } + + public static void main(String[] args) { + Solution solution = new Solution(); + ListNodeMe listNode0 = ListNodeMe.createTestData("[1,3,5,7,9]"); + ListNodeMe listNode1 = ListNodeMe.createTestData("[1,2,4,6,8,10]"); + ListNodeMe.print(listNode0); + ListNodeMe.print(listNode1); + ListNodeMe.print(solution.mergeTwoLists(listNode0, listNode1)); + } + + private ListNodeMe mergeTwoLists(ListNodeMe listNode0, ListNodeMe listNode1) { + ListNodeMe header = new ListNodeMe(-1); + ListNodeMe temp = header; + while (listNode0 != null && listNode1 != null) { + if (listNode0.data < listNode1.data) { + temp.next = listNode0; + listNode0 = listNode0.next; + } else { + temp.next = listNode1; + listNode1 = listNode1.next; + } + temp = temp.next; + } + temp.next = listNode0 == null ? listNode1 : listNode0; + return header.next; + } } \ No newline at end of file diff --git a/src/com/blankj/easy/_0083/Solution.java b/src/com/blankj/easy/_0083/Solution.java index 222dec80..e2a10aec 100644 --- a/src/com/blankj/easy/_0083/Solution.java +++ b/src/com/blankj/easy/_0083/Solution.java @@ -1,6 +1,14 @@ package com.blankj.easy._083; import com.blankj.structure.ListNode; +import com.blankj.structure.ListNodeMe; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static java.lang.System.in; +import static java.lang.System.out; /** *@@ -24,9 +32,135 @@ public ListNode deleteDuplicates(ListNode head) { return head; } - public static void main(String[] args) { + public static void main2(String[] args) { Solution solution = new Solution(); ListNode.print(solution.deleteDuplicates(ListNode.createTestData("[1,1,2]"))); ListNode.print(solution.deleteDuplicates(ListNode.createTestData("[1,1,2,3,3]"))); } + + public static void main_me(String[] args) { + Solution solution = new Solution(); + // 升序的链表排重很好做了 + ListNodeMe listNode1 = ListNodeMe.createTestData("[1,2,2,4,4,6,8,10]"); + ListNodeMe.print(listNode1); + solution.deleteDuplicates2(listNode1); + } + + public static void main3(String[] args) { + Solution solution = new Solution(); +// ListNodeMe listNode1 = ListNodeMe.createTestData("[1,2,2,4,4,6,8,10]"); + ListNodeMe listNode1 = ListNodeMe.createCirlceList("[1,2,2,4,4,6,8,10]"); + boolean looperList = solution.isLooperList(listNode1); + out.println("is cirlce list ? " + looperList); + } + + public static void main(String[] args) { + Solution solution = new Solution(); + ListNodeMe listNode1 = ListNodeMe.createTestData("[1,2,3,4,5,6,8,10]"); +// ListNodeMe.print(solution.reverseList2(listNode1)); + listNode1 = solution.deleteByIndex(listNode1, 3); + + ListNodeMe.print(listNode1); + } + + private void deleteDuplicates2(ListNodeMe listNode1) { + ListNodeMe temp = listNode1; + while (temp != null && temp.next != null) { + if (temp.data == temp.next.data) { + temp.next = temp.next.next; + } else { + temp = temp.next; + } + } + ListNodeMe.print(listNode1); + } + + /** + * 判断是否有环 + * @param temp + * @return + */ + private boolean isLooperList(ListNodeMe temp) { + Object o = new Object(); + Mapmap = new HashMap<>(); + while (temp != null) { + Object put = map.put(temp, o); + if (put != null) { + return true; + } + temp = temp.next; + } + return false; + } + + public static ListNodeMe reverseList2(ListNodeMe current) { + ListNodeMe pre = null; + ListNodeMe next = null; + while (current != null) { + // 第一步: 保存下一个节点,因为需要打断 + next = current.next; + // 第二步:打断 + current.next = pre; + + //后面两步为了下一次循环做准备 + pre = current; + current = next; + } + return pre; + } + + public static ListNodeMe reverseList3(ListNodeMe current) { + ListNodeMe next = null; + ListNodeMe pre = null; + while (current != null) { + // 保存next指针 + next = current.next; + // 打断next指针,指向前一个节点 + current.next = pre; + + // 为下一次循环做准备, 将pre节点指向当前节点, 将当前节点指向下一个节点,进入下一次循环 + pre = current; + current = next; + } + return pre; + } + + /** + * 删除第index个元素, 从0开始 "[1,2,3,4,5,6,8,10]" 2 + * @param current + * @param index + */ + public ListNodeMe deleteByIndex(ListNodeMe current, int index) { // 2 + ListNodeMe orign = current; + if (index == 0) { + return orign.next; + } + ListNodeMe pre = null; + while (index > 0) { + pre = orign; + orign = orign.next; + index--; + } + pre.next = orign.next; + orign.next = null; + return current; + } + + /** + * 反转列表 + * @param current + * @return + */ + public static ListNodeMe reverseList(ListNodeMe current) { + ListNodeMe pre = null; + ListNodeMe next = null; + while (current != null) { + next = current.next; + current.next = pre; + + pre = current; + current = next; + } + return pre; + } } diff --git a/src/com/blankj/easy/_0104/Solution.java b/src/com/blankj/easy/_0104/Solution.java index 8b682219..5dae0f9c 100644 --- a/src/com/blankj/easy/_0104/Solution.java +++ b/src/com/blankj/easy/_0104/Solution.java @@ -2,6 +2,9 @@ import com.blankj.structure.TreeNode; +import com.blankj.structure.TreeNodeMe; + +import static java.lang.System.out; /** * @@ -17,10 +20,44 @@ public int maxDepth(TreeNode root) { return 1 + Math.max(maxDepth(root.left), maxDepth(root.right)); } + public static void main_author(String[] args) { + Solution solution = new Solution(); +// System.out.println(solution.maxDepth(TreeNode.createTestData("[]"))); + TreeNode rootNode = TreeNode.createTestData("[1,2,2,3,4,4,3]"); + int depth = solution.maxDepth(rootNode); + out.println(depth); + TreeNode.print(rootNode); +// System.out.println(solution.maxDepth(TreeNode.createTestData("[9,-42,-42,null,76,76,null,null,13,null,13]"))); + } + public static void main(String[] args) { Solution solution = new Solution(); - System.out.println(solution.maxDepth(TreeNode.createTestData("[]"))); - System.out.println(solution.maxDepth(TreeNode.createTestData("[1,2,2,3,4,4,3]"))); - System.out.println(solution.maxDepth(TreeNode.createTestData("[9,-42,-42,null,76,76,null,null,13,null,13]"))); +// TreeNodeMe rootNode = TreeNodeMe.createTestData("[1,2,2,3,4,4,3,5,6]"); + TreeNodeMe rootNode = TreeNodeMe.createTestData("[0,1,2,3,4]"); + int depth = solution.maxDepthMe(rootNode); + out.println(depth); +// TreeNodeMe.print(rootNode); + + } + + /** + * 深度搜索 + * 0 -> 1 -> 3 -> 3.left return 1 -> 3.right return 1-> max(1,1) -> + * 1.left return 2 -> 4 -> 4.left is null return 1 -> 4.right is null return 1 -> + * -> max(1, 1) - > 1.right return 2 -> max.(2, 2) return 2 -> + * 0.left return 3 -> 2 -> 2.left -> 2.left return 1 -> 2.right -> 2.right return 1 + * -> max(1, 1) ->0.right return 2 -> max(3, 2) -> return 3 + * @param root + * @return + */ + public int maxDepthMe(TreeNodeMe root) { + if (root == null) { + return 0; + } + out.println("经过了此节点值为:" +root.value); + int leftDepth = maxDepthMe(root.left) + 1; + int rightDepth = maxDepthMe(root.right) + 1; + return Math.max(leftDepth, rightDepth); } + } diff --git a/src/com/blankj/easy/_0107/Solution.java b/src/com/blankj/easy/_0107/Solution.java index c0064e92..c2ad2cfc 100644 --- a/src/com/blankj/easy/_0107/Solution.java +++ b/src/com/blankj/easy/_0107/Solution.java @@ -2,9 +2,14 @@ import com.blankj.structure.TreeNode; +import com.blankj.structure.TreeNodeMe; +import java.util.ArrayDeque; import java.util.LinkedList; import java.util.List; +import java.util.Queue; + +import static java.lang.System.out; /** *@@ -17,13 +22,13 @@ public class Solution { public List> levelOrderBottom(TreeNode root) { List
> list = new LinkedList<>(); - helper(list, root, 0); + helper2(list, root, 0); return list; } private void helper(List
> list, TreeNode root, int level) { if (root == null) return; - if (level >= list.size()) { + if (level >= list.size()) { // 每经过一层添加一个list list.add(0, new LinkedList<>()); } helper(list, root.left, level + 1); @@ -31,10 +36,80 @@ private void helper(List
> list, TreeNode root, int level) { list.get(list.size() - level - 1).add(root.val); } + private void helper2(List
> list, TreeNode root, int level) { + if (root == null) return; + if (level >= list.size()) { // 每经过一层添加一个list + list.add(0, new LinkedList<>()); + } + helper2(list, root.left, level + 1); + helper2(list, root.right, level + 1); + out.print(root.val + " "); // 在这里控制(前中后,指的是中间节点的访问顺序)序 + list.get(list.size() - level - 1).add(root.val); + } + + public static void main2(String[] args) { + Solution solution = new Solution(); +// System.out.println(solution.levelOrderBottom(TreeNode.createTestData("[]"))); + List
> lists = solution.levelOrderBottom(TreeNode.createTestData("[1,2,2,3,4,4,3]")); +// out.println(lists); +// System.out.println(solution.levelOrderBottom(TreeNode.createTestData("[9,-42,-42,null,76,76,null,null,13,null,13]"))); + } + + /** + * 0 + * / \ + * 1 2 + * / \ / \ + * 3 4 5 6 + * @param args + */ public static void main(String[] args) { Solution solution = new Solution(); - System.out.println(solution.levelOrderBottom(TreeNode.createTestData("[]"))); - System.out.println(solution.levelOrderBottom(TreeNode.createTestData("[1,2,2,3,4,4,3]"))); - System.out.println(solution.levelOrderBottom(TreeNode.createTestData("[9,-42,-42,null,76,76,null,null,13,null,13]"))); + TreeNodeMe treeNodes = TreeNodeMe.createTestData("[0,1,2,3,4,5,6]"); + List
> lists = solution.depthSearch(treeNodes); +// out.println(lists); + solution.levelSearch(treeNodes); } + + public List
> depthSearch(TreeNodeMe root) { + List
> list = new LinkedList<>(); + out.print("深度搜索: "); + depth(root); + out.println(); + return list; + } + + /** + * 这里就是深度遍历(也就是前序遍历) + * @param root + */ + private void depth(TreeNodeMe root) { + if (root == null) return; + out.print(root.value + " "); + depth(root.left); + depth(root.right); + + } + + /** + * 广度 0 1 2 3 4 5 6 + * @param root + */ + private void levelSearch(TreeNodeMe root) { + if (root == null) return; + Queue
queue = new ArrayDeque(); + queue.add(root); + out.print("广度搜索: "); + while (!queue.isEmpty()) { + TreeNodeMe header = queue.remove(); + out.print(header.value + " "); + if (header.left != null) { + queue.add(header.left); + } + if (header.right != null) { + queue.add(header.right); + } + } + } + } diff --git a/src/com/blankj/easy/_0107/TreeTest.java b/src/com/blankj/easy/_0107/TreeTest.java new file mode 100644 index 00000000..22a3f0c9 --- /dev/null +++ b/src/com/blankj/easy/_0107/TreeTest.java @@ -0,0 +1,109 @@ + +import java.util.ArrayDeque; +import java.util.Stack; + +public class TreeTest { + static class TreeNode { + int value; + TreeNode left; + TreeNode right; + + public TreeNode(int value) { + this.value = value; + } + } + + TreeNode root; + + public TreeTest(int[] array) { + root = makeBinaryTreeByArray(array, 1); + } + + /** + * 采用递归的方式创建一颗二叉树 + * 传入的是二叉树的数组表示法 + * 构造后是二叉树的二叉链表表示法 + */ + public static TreeNode makeBinaryTreeByArray(int[] array, int index) { + if (index < array.length) { + int value = array[index]; + if (value != 0) { + TreeNode t = new TreeNode(value); + array[index] = 0; + t.left = makeBinaryTreeByArray(array, index * 2); + t.right = makeBinaryTreeByArray(array, index * 2 + 1); + return t; + } + } + return null; + } + + /** + * 深度优先遍历,相当于先根遍历 + * 采用非递归实现 + * 需要辅助数据结构:栈 + */ + public void depthOrderTraversal() { + if (root == null) { + System.out.println("empty tree"); + return; + } + // ArrayDeque stack=new ArrayDeque (); + // 0,13,65,5,97,25,0,37,22,0,4,28,0,0,32,0 + Stack stack = new Stack(); //也可以用栈实现 + stack.push(root); + while (stack.isEmpty() == false) { + TreeNode node = stack.pop(); + System.out.print(node.value + " "); // 先访问自己 + if (node.right != null) { + stack.push(node.right); + } + if (node.left != null) { // 最后访问左节点 + stack.push(node.left); + } + } + System.out.print("\n"); + } + + /** + * 广度优先遍历 + * 采用非递归实现 + * 需要辅助数据结构:队列 + */ + public void levelOrderTraversal() { + if (root == null) { + System.out.println("empty tree"); + return; + } + ArrayDeque queue = new ArrayDeque (); + queue.add(root); + while (queue.isEmpty() == false) { + TreeNode node = queue.remove(); + System.out.print(node.value + " "); + if (node.left != null) { + queue.add(node.left); + } + if (node.right != null) { + queue.add(node.right); + } + } + System.out.print("\n"); + } + + /** + * 13 + * / \ + * 65 5 + * / \ \ + * 97 25 37 + * / /\ / + * 22 4 28 32 + */ + public static void main(String[] args) { + int[] arr = {0, 13, 65, 5, 97, 25, 0, 37, 22, 0, 4, 28, 0, 0, 32, 0}; + TreeTest tree = new TreeTest(arr); + tree.depthOrderTraversal(); //深度优先: 深度就是前序 13 65 97 22 25 4 28 5 37 32 + tree.levelOrderTraversal(); //广度优先: 13 65 5 97 25 37 22 4 28 32 + } + +} diff --git a/src/com/blankj/structure/ListNodeMe.java b/src/com/blankj/structure/ListNodeMe.java new file mode 100644 index 00000000..b6c3d05c --- /dev/null +++ b/src/com/blankj/structure/ListNodeMe.java @@ -0,0 +1,69 @@ +package com.blankj.structure; + +import static java.lang.System.out; + +public class ListNodeMe { + public int data; + public ListNodeMe next; + + public ListNodeMe(int data) { + this.data = data; + } + + /** + * 创建测试数据 + * + * @param data [XX,XX,XX] + * @return {@link ListNode} + */ + public static ListNodeMe createTestData(String data) { + if ("[]".equals(data)) { + return null; + } + String substring = data.substring(1, data.length()-1); + out.println(substring); + String[] arr = substring.split(","); + ListNodeMe[] nodeArr = new ListNodeMe[arr.length]; + nodeArr[0] = new ListNodeMe(Integer.parseInt(arr[0])); + for (int i = 1; i < arr.length; i++) { + nodeArr[i] = new ListNodeMe(Integer.parseInt(arr[i])); + nodeArr[i-1].next = nodeArr[i]; + } + return nodeArr[0]; + } + + /** + * 创建带有环的链表 + * @param data + * @return + */ + public static ListNodeMe createCirlceList(String data) { + if ("[]".equals(data)) { + return null; + } + String substring = data.substring(1, data.length()-1); + out.println(substring); + String[] arr = substring.split(","); + ListNodeMe[] nodeArr = new ListNodeMe[arr.length]; + nodeArr[0] = new ListNodeMe(Integer.parseInt(arr[0])); + for (int i = 1; i < arr.length; i++) { + nodeArr[i] = new ListNodeMe(Integer.parseInt(arr[i])); + nodeArr[i-1].next = nodeArr[i]; + } + nodeArr[arr.length - 1].next = nodeArr[0]; + return nodeArr[0]; + } + + public static void print(ListNodeMe nodeMe) { + while (nodeMe != null) { + out.print(nodeMe.data + " "); + nodeMe = nodeMe.next; + } + out.println(); + } + + public static void main(String[] args) { + ListNodeMe nodeMe = ListNodeMe.createTestData("[1,3,5,7,9]"); + print(nodeMe); + } +} diff --git a/src/com/blankj/structure/TreeNode.java b/src/com/blankj/structure/TreeNode.java index 7addb8e4..bc8cf278 100644 --- a/src/com/blankj/structure/TreeNode.java +++ b/src/com/blankj/structure/TreeNode.java @@ -28,14 +28,17 @@ public static TreeNode createTestData(String data) { if (data.equals("[]")) return null; data = data.substring(1, data.length() - 1); String[] split = data.split(","); - int len = len = split.length; + int len = split.length; + // 数组保存所有节点 TreeNode[] treeNodes = new TreeNode[len]; - data = data.substring(1, data.length() - 1); + // [1,2,2,3,4,4,3] for (int i = 0; i < len; i++) { if (!split[i].equals("null")) { + // 给节点赋值, 但是没有引用关系 treeNodes[i] = new TreeNode(Integer.valueOf(split[i])); } } + // 建立引用关系 for (int i = 0; i < len; i++) { if (treeNodes[i] != null) { int leftIndex = i * 2 + 1; diff --git a/src/com/blankj/structure/TreeNodeMe.java b/src/com/blankj/structure/TreeNodeMe.java new file mode 100644 index 00000000..26c67888 --- /dev/null +++ b/src/com/blankj/structure/TreeNodeMe.java @@ -0,0 +1,73 @@ +package com.blankj.structure; + +public class TreeNodeMe { + public int value; + public TreeNodeMe left; + public TreeNodeMe right; + + public TreeNodeMe(int value) { + this.value = value; + } + + public static TreeNodeMe createTestData(String data) { + // [1,2,2,3,4,4,3] + data = data.substring(1, data.length() - 1); + String[] split = data.split(","); + int len = split.length; + TreeNodeMe treeNodes[] = new TreeNodeMe[len]; + // 给数组赋值 + for (int i = 0; i < len; i++) { + treeNodes[i] = new TreeNodeMe(Integer.parseInt(split[i])); // 异常未捕获 + } + // 建立引用关系 + for (int i = 0; i < len; i++) { + int leftIndex = i * 2 + 1; + int rightIndex = leftIndex + 1; + if (leftIndex < len) { + treeNodes[i].left = treeNodes[leftIndex]; + } + if (rightIndex < len) { + treeNodes[i].right = treeNodes[rightIndex]; + } + } + return treeNodes[0]; + } + + private static final String space = " "; + + /** + * 竖向打印二叉树 + * + * @param root 二叉树根节点 + */ + public static void print(TreeNodeMe root) { + print(root, 0); + } + + private static void print(TreeNodeMe node, int deep) { + if (node == null) { + printSpace(deep); + System.out.println("#"); + return; + } + print(node.right, deep + 1); + printSpace(deep); + printNode(node.value); + print(node.left, deep + 1); + } + + private static void printSpace(int count) { + for (int i = 0; i < count; i++) { + System.out.printf(space); + } + } + + private static void printNode(int val) { + StringBuilder res = new StringBuilder(val + "<"); + int spaceNum = space.length() - res.length(); + for (int i = 0; i < spaceNum; i++) { + res.append(" "); + } + System.out.println(res); + } +}