diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java index c347f45..c2251b0 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java @@ -4,7 +4,7 @@ package com.markilue.leecode.tree; import java.util.List; -import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1; +import static com.markilue.leecode.tree.T03_InorderTraversal.inorderTraversal1; /** * 删除二叉排序树的某个节点 diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java index 52fe779..e65b222 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNodeII.java @@ -4,7 +4,7 @@ import org.junit.Test; import java.util.List; -import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1; +import static com.markilue.leecode.tree.T03_InorderTraversal.inorderTraversal1; /** * @BelongsProject: Leecode diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/PostOrderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/T02_PostOrderTraversal.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/PostOrderTraversal.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T02_PostOrderTraversal.java index 41bef86..864141e 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/PostOrderTraversal.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T02_PostOrderTraversal.java @@ -13,7 +13,7 @@ import java.util.*; * 给你二叉树的根节点 root ,返回它节点值的 前序 遍历。 * @Version: 1.0 */ -public class PostOrderTraversal { +public class T02_PostOrderTraversal { @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/T03_InorderTraversal.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T03_InorderTraversal.java index e9ec1a8..7160d4f 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/InorderTraversal.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T03_InorderTraversal.java @@ -8,7 +8,7 @@ import java.util.Stack; /** * 中序遍历二叉排序树 */ -public class InorderTraversal { +public class T03_InorderTraversal { public static void main(String[] args) { diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/LevelOrder.java b/Leecode/src/main/java/com/markilue/leecode/tree/T04_LevelOrder.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/LevelOrder.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T04_LevelOrder.java index 60ac632..f30c27c 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/LevelOrder.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T04_LevelOrder.java @@ -14,7 +14,7 @@ import java.util.*; * 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 * @Version: 1.0 */ -public class LevelOrder { +public class T04_LevelOrder { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java b/Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java index b9c24e1..e1ee3c8 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/TrimBST.java @@ -2,11 +2,9 @@ package com.markilue.leecode.tree; import org.junit.Test; -import java.util.HashMap; import java.util.List; -import java.util.Stack; -import static com.markilue.leecode.tree.InorderTraversal.inorderTraversal1; +import static com.markilue.leecode.tree.T03_InorderTraversal.inorderTraversal1; /** * @BelongsProject: Leecode diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T02_PostOrderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T02_PostOrderTraversal.java new file mode 100644 index 0000000..984cb52 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T02_PostOrderTraversal.java @@ -0,0 +1,220 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; +import com.markilue.leecode.tree.TreeUtils; +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-05 10:25 + *@Description: + * TODO 二刷leecode145题 二叉树的后序遍历: + * 给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。 + *@Version: 1.0 + */ +public class T02_PostOrderTraversal { + + @Test + public void test() { + ArrayList list = new ArrayList<>(Arrays.asList(3,1,2,5,6,7,8,10)); + TreeNode root = TreeUtils.structureTree(list, 0); + System.out.println(postorderTraversal3(root)); + + } + + /** + * 思路:递归法 + * @param root + * @return + */ + List result; + public List postorderTraversal(TreeNode root) { + result=new ArrayList<>(); + postTraversal(root); + return result; + + } + public void postTraversal(TreeNode root) { + if(root==null){ + return; + } + + postTraversal(root.left); + postTraversal(root.right); + result.add(root.val); + + } + + + /** + * 思路:stack迭代法:中右左——>反序:左右中 + * @param root + * @return + */ + public List postorderTraversal1(TreeNode root) { + List result = new ArrayList<>(); + + if(root==null){ + return result; + } + + Stack stack = new Stack<>(); + stack.push(root); + + while(!stack.isEmpty()){ + + TreeNode node = stack.pop(); + result.add(node.val); + if(node.left!=null){ + stack.push(node.left); + } + if(node.right!=null){ + stack.push(node.right); + } + + } + + int size = result.size(); + List result1 = new ArrayList<>(); + while (size>0){ + result1.add(result.get(--size)); + } + return result1; + + } + + + /** + * 思路:优化stack迭代法:改变树结构 + * @param root + * @return + */ + public List postorderTraversal2(TreeNode root) { + List result = new ArrayList<>(); + + if(root==null){ + return result; + } + + Stack stack = new Stack<>(); + TreeNode cur=root; + + while(cur!=null||!stack.isEmpty()){ + + if(cur!=null){ + stack.push(cur); + cur=cur.left; + }else { + TreeNode node = stack.peek(); + if(node.right!=null){ + cur=node.right; + node.right=null;//核心是把right置空,防止下次在遍历到,但是会改变原本的树结构 + }else { + //右边没有了,安心处理node + result.add(node.val); + stack.pop(); + } + } + + } + + + return result; + + } + + /** + * 官方不改变树结构的stack法,使用一个pre记录之前的node,如果之前的node=root.right就说明右边的已经遍历完了 + * @param root + * @return + */ + public List postorderTraversal4(TreeNode root) { + List res = new ArrayList(); + if (root == null) { + return res; + } + + Deque stack = new LinkedList(); + TreeNode prev = null; + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + if (root.right == null || root.right == prev) { + //核心在于prev指针记录之前是否遍历他的右边 + res.add(root.val); + prev = root; + root = null; + } else { + stack.push(root); + root = root.right; + } + } + return res; + } + + + + + /** + * 思路:Morris遍历:在不改变结构的情况下直接的Morris遍历是不行的,还是得中右左然后反向 + * @param root + * @return + */ + public List postorderTraversal3(TreeNode root) { + List result = new ArrayList<>(); + + if(root==null){ + return result; + } + + TreeNode cur=root; + + while (cur!=null){ + TreeNode node=cur.right; + + if(node!=null){ + //存在右节点,寻找右子节点的最左节点 + while (node.left!=cur&&node.left!=null){ + node=node.left; + } + //判断是从啥条件出来的 + if(node.left==null){ + //第一次遍历到这 + node.left=cur;//将其连接 + result.add(cur.val); + //放心将节点右移 + cur=cur.right; + }else if(node.left==cur){ + //第二次遍历到这 + cur=cur.left; + node.left=null; + } + }else { + //右边为空了,遍历左节点去 + result.add(cur.val); + cur=cur.left; + } + } + + + int size = result.size(); + List result1 = new ArrayList<>(); + while (size>0){ + result1.add(result.get(--size)); + } + return result1; + + + + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T03_InorderTraversal.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T03_InorderTraversal.java new file mode 100644 index 0000000..91c1e87 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T03_InorderTraversal.java @@ -0,0 +1,119 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; +import com.markilue.leecode.tree.TreeUtils; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Stack; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-05 11:35 + *@Description: + * TODO 二刷力扣94题 二叉树的中序遍历: + * 给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。 + *@Version: 1.0 + */ +public class T03_InorderTraversal { + + @Test + public void test() { + ArrayList list = new ArrayList<>(Arrays.asList(3,1,2,5,6,7,8,10)); + TreeNode root = TreeUtils.structureTree(list, 0); + System.out.println(inorderTraversal2(root)); + + } + + /** + * 思路:递归法 + * @param root + * @return + */ + List result; + public List inorderTraversal(TreeNode root) { + result=new ArrayList<>(); + midTraversal(root); + return result; + } + public void midTraversal(TreeNode root) { + if(root==null){ + return; + } + midTraversal(root.left); + result.add(root.val); + midTraversal(root.right); + } + + + /** + * 思路:stack非递归法 + * @param root + * @return + */ + public List inorderTraversal1(TreeNode root) { + ArrayList result = new ArrayList<>(); + if(root==null){ + return result; + } + Stack stack = new Stack<>(); + TreeNode cur=root; + + while (cur!=null||!stack.isEmpty()){ + if(cur!=null){ + stack.push(cur); + cur=cur.left; + }else { + TreeNode node = stack.pop(); + result.add(node.val); + cur=node.right;//看看他的右边 + } + } + + return result; + } + + + /** + * 思路:Morris遍历 + * @param root + * @return + */ + public List inorderTraversal2(TreeNode root) { + List result = new ArrayList<>(); + if(root==null){ + return result; + } + + TreeNode cur=root; + while (cur!=null){ + TreeNode node=cur.left; + if(node!=null){ + while(node.right!=cur&&node.right!=null){ + node=node.right; + } + + if(node.right==null){ + node.right=cur; + cur=cur.left; + }else { + //左边节点遍历完了 + node.right=null; + result.add(cur.val); + cur=cur.right; + } + }else { + result.add(cur.val);//左边节点空了 + cur=cur.right; + } + } + + + return result; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T041_LevelOrderBottom.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T041_LevelOrderBottom.java new file mode 100644 index 0000000..586ae70 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T041_LevelOrderBottom.java @@ -0,0 +1,118 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; +import com.markilue.leecode.tree.TreeUtils; +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-05 12:15 + *@Description: + * TODO 力扣107题 二叉树的层序遍历 II: + * 给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 + * (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历) + *@Version: 1.0 + */ +public class T041_LevelOrderBottom { + + @Test + public void test() { + ArrayList list = new ArrayList<>(Arrays.asList(3,9,20,null,null,15,7)); + TreeNode root = TreeUtils.structureTree(list, 0); + System.out.println(levelOrderBottom1(root)); + + } + + /** + * 思路:queue先层序后反向 + * 速度击败91.28%,内存击败6.48% + * @param root + * @return + */ + public List> levelOrderBottom(TreeNode root) { + List> result = new ArrayList<>(); + if(root==null){ + return result; + } + + Deque queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()){ + ArrayList cur = new ArrayList<>(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + cur.add(node.val); + if(node.left!=null)queue.offer(node.left); + if(node.right!=null)queue.offer(node.right); + } + result.add(cur); + } + Collections.reverse(result); + return result; + } + + + /** + * 思路:dfs深度优先递归 + * @param root + * @return + */ + List> result = new ArrayList<>(); + int maxDepth=0; + public List> levelOrderBottom1(TreeNode root) { + + dfs(root,0); + Collections.reverse(result); + return result; + } + public void dfs(TreeNode root,int deep) { + if(root==null){ + return; + } + if(result.size()==deep){ + result.add(new ArrayList<>()); + } + dfs(root.left,deep+1); + dfs(root.right,deep+1); + result.get(deep).add(root.val); + } + + + /** + * 官方直接加在头部法,避免反向 + * @param root + * @return + */ + public List> levelOrderBottom2(TreeNode root) { + List> levelOrder = new LinkedList>(); + if (root == null) { + return levelOrder; + } + Queue queue = new LinkedList(); + queue.offer(root); + while (!queue.isEmpty()) { + List level = new ArrayList(); + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + level.add(node.val); + TreeNode left = node.left, right = node.right; + if (left != null) { + queue.offer(left); + } + if (right != null) { + queue.offer(right); + } + } + levelOrder.add(0, level); + } + return levelOrder; + } + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T04_LevelOrder.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T04_LevelOrder.java new file mode 100644 index 0000000..2885331 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T04_LevelOrder.java @@ -0,0 +1,78 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; +import com.markilue.leecode.tree.TreeUtils; +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-05 11:58 + *@Description: + * TODO 二刷力扣102题 二叉树的层序遍历: + * 给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。 + *@Version: 1.0 + */ +public class T04_LevelOrder { + + @Test + public void test() { + ArrayList list = new ArrayList<>(Arrays.asList(3,9,20,null,null,15,7)); + TreeNode root = TreeUtils.structureTree(list, 0); + System.out.println(levelOrder(root)); + + } + + /** + * 思路:队列法 + * @param root + * @return + */ + public List> levelOrder(TreeNode root) { + List> result = new ArrayList<>(); + if(root==null){ + return result; + } + + Deque queue = new LinkedList<>(); + queue.offer(root); + + while (!queue.isEmpty()){ + int size = queue.size(); + List cur = new ArrayList<>();//每层result + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + cur.add(node.val); + if(node.left!=null)queue.offer(node.left); + if(node.right!=null)queue.offer(node.right); + } + result.add(cur); + } + return result; + + } + + /** + * 官方最快:递归法,虽然是深度优先,但是他通过ans.get(depth)获取到第deep层的数列 + */ + List> ans = new ArrayList<>(); + public List> levelOrder2(TreeNode root) { + dfs(root, 0); + return ans; + } + + public void dfs(TreeNode node, int depth) { + if (node == null) { + return; + } + if (ans.size() == depth) { + ans.add(new ArrayList<>()); + } + ans.get(depth).add(node.val); + dfs(node.left, depth + 1); + dfs(node.right, depth + 1); + } +}