diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/T10_SumOfLeftLeaves.java b/Leecode/src/main/java/com/markilue/leecode/tree/T10_SumOfLeftLeaves.java new file mode 100644 index 0000000..75c3cbb --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T10_SumOfLeftLeaves.java @@ -0,0 +1,133 @@ +package com.markilue.leecode.tree; + +import org.junit.Test; + +import java.util.*; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-10 10:12 + *@Description: + * TODO 力扣404 左子树之和: + * 给定二叉树的根节点 root ,返回所有左叶子之和。 + *@Version: 1.0 + */ +public class T10_SumOfLeftLeaves { + + @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(sumOfLeftLeaves(root)); + + } + + @Test + public void test1() { + ArrayList list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5)); + TreeNode root = TreeUtils.structureTree(list, 0); + System.out.println(sumOfLeftLeaves(root)); + + } + + /** + * 思路:左叶子节点(叶子节点:左右没有节点,且是左节点) 迭代法中序遍历不处理中节点即可 + * 速度击败10.5%,内存击败80.37% + * @param root + * @return + */ + public int sumOfLeftLeaves(TreeNode root) { + int sum = 0; + if (root == null) { + return sum; + } + Stack stack = new Stack<>(); + TreeNode cur = root; + TreeNode jin = root;//不让他加入的节点 + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + if (cur != jin && cur.left == null && cur.right == null) { + sum += cur.val; + } + stack.push(cur); + cur = cur.left; + } else { + cur = stack.pop(); + cur = cur.right; + jin = cur;//刚刚进入右节点则不能让他加 + } + } + return sum; + + } + + /** + * 思路:左叶子节点(叶子节点:左右没有节点,且是左节点) 递归法中序遍历不处理中节点即可 + * 速度击败100%,内存击败84.12% + * @param root + * @return + */ + public int sumOfLeftLeaves1(TreeNode root) { + if (root == null) { + return 0; + } + return travelLeftLeaves1(root, null); + } + + /** + * 遍历,看看node是不是pre的左节点来判断 + * @param node + * @param pre + * @return + */ + public int travelLeftLeaves1(TreeNode node, TreeNode pre) { + if (node == null) {//节点为null不用继续遍历 + return 0; + } + if (pre != null && pre.left == node && node.left == null && node.right == null) { + return node.val;//左叶子节点,加上这个值 + } + return travelLeftLeaves1(node.left, node) + travelLeftLeaves1(node.right, node); + } + + + /** + * 官方BFS:之前都是dfs这里试试BFS法,核心在于不是处理当前节点,而是在父节点判断左节点是不是叶子结点 + * 速度击败100%,内存击败47.69% + * @param root + * @return + */ + public int sumOfLeftLeaves3(TreeNode root) { + if (root == null) { + return 0; + } + + Queue queue = new LinkedList(); + queue.offer(root); + int ans = 0; + while (!queue.isEmpty()) { + TreeNode node = queue.poll(); + if (node.left != null) { + if (isLeafNode(node.left)) { + ans += node.left.val; + } else { + queue.offer(node.left); + } + } + if (node.right != null) { + if (!isLeafNode(node.right)) { + queue.offer(node.right); + } + } + } + return ans; + } + + public boolean isLeafNode(TreeNode node) { + return node.left == null && node.right == null; + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/T11_FindBottomLeftValue.java b/Leecode/src/main/java/com/markilue/leecode/tree/T11_FindBottomLeftValue.java new file mode 100644 index 0000000..87e1203 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T11_FindBottomLeftValue.java @@ -0,0 +1,75 @@ +package com.markilue.leecode.tree; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree + *@Author: dingjiawen + *@CreateTime: 2023-01-10 10:53 + *@Description: + * TODO 力扣513题 找左下角的值: + * 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 + * 假设二叉树中至少有一个节点。 + *@Version: 1.0 + */ +public class T11_FindBottomLeftValue { + + /** + * 思路:不仅要最底层,还要最左;事实上层序遍历就是一个很好地选择 + * 速度击败13.85%,内存击败45.94% 2ms + * @param root + * @return + */ + public int findBottomLeftValue(TreeNode root) { + int value = 0; + if (root == null) { + return value; + } + Queue queue = new LinkedList<>(); + queue.offer(root); + while (!queue.isEmpty()) { + int size = queue.size(); + for (int i = 0; i < size; i++) { + TreeNode node = queue.poll(); + if (i == 0) { + //每层的最左边 + value = node.val; + } + if (node.left != null) queue.offer(node.left); + if (node.right != null) queue.offer(node.right); + } + } + return value; + + } + + + /** + * 思路:不仅要最底层,还要最左;事实上层序遍历就是一个很好地选择,尝试递归DFS + * 速度击败100%,内存击败65.25% 0ms + * @param root + * @return + */ + public int findBottomLeftValue1(TreeNode root) { + find(root,0); + return result.get(result.size()-1); + + } + + //记录每层最右 + List result=new ArrayList<>(); + public void find(TreeNode node, int deep) { + if (node == null) { + return; + } + if(result.size()==deep){ + result.add(node.val); + } + find(node.left,deep+1); + find(node.right,deep+1); + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/HasPathSum.java b/Leecode/src/main/java/com/markilue/leecode/tree/T12_HasPathSum.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/HasPathSum.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T12_HasPathSum.java index 937151e..19b6420 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/HasPathSum.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T12_HasPathSum.java @@ -18,7 +18,7 @@ import java.util.Stack; * 叶子节点 是指没有子节点的节点。 * @Version: 1.0 */ -public class HasPathSum { +public class T12_HasPathSum { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/PathSum.java b/Leecode/src/main/java/com/markilue/leecode/tree/T13_PathSum.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/PathSum.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T13_PathSum.java index f58d50a..9803ef2 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/PathSum.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T13_PathSum.java @@ -14,7 +14,7 @@ import java.util.*; * 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 * @Version: 1.0 */ -public class PathSum { +public class T13_PathSum { @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/BuildTree.java b/Leecode/src/main/java/com/markilue/leecode/tree/T14_BuildTree.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/BuildTree.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T14_BuildTree.java index 8f9c5e5..1748a99 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/BuildTree.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T14_BuildTree.java @@ -13,7 +13,7 @@ import java.util.*; * 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树。 * @Version: 1.0 */ -public class BuildTree { +public class T14_BuildTree { @Test diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T12_HasPathSum.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T12_HasPathSum.java new file mode 100644 index 0000000..7bef889 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T12_HasPathSum.java @@ -0,0 +1,83 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; +import org.junit.Test; + +import java.util.Stack; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-10 11:33 + *@Description: + * TODO 力扣112题 二刷路径总和: + * 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。 + * 判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。 + * 如果存在,返回 true ;否则,返回 false 。 + * 叶子节点 是指没有子节点的节点。 + *@Version: 1.0 + */ +public class T12_HasPathSum { + @Test + public void test(){ + Integer sum=1000; + int i = sum.intValue(); + System.out.println(i); + } + + /** + * 思路:核心就在于在叶子结点时就判断targetSum;DFS + * @param root + * @param targetSum + * @return + */ + public boolean hasPathSum(TreeNode root, int targetSum) { + if (root == null) {//避免开始就是空的情况 + return false; + } + if (root.left == null && root.right == null) {//在叶子结点就处理逻辑 + return root.val == targetSum; + } + int nextTarget = targetSum - root.val; + return hasPathSum(root.left, nextTarget) || hasPathSum(root.right, nextTarget); + + } + + /** + * 思路:非递归法DFS + * 速度击败6.83%,内存击败58.93% + * @param root + * @param targetSum + * @return + */ + public boolean hasPathSum1(TreeNode root, int targetSum) { + if (root == null) {//避免开始就是空的情况 + return false; + } + Stack stack = new Stack<>(); + Stack stackSum = new Stack<>(); + stack.push(root); + stackSum.push(0); + while (!stack.isEmpty()){ + TreeNode node = stack.pop(); + Integer sum = stackSum.pop(); + sum+=node.val; + if(node.left==null&&node.right==null){ + if(sum.intValue()==targetSum){ + return true; + } + } + if(node.left!=null){ + stack.push(node.left); + stackSum.push(sum); + } + if(node.right!=null){ + stack.push(node.right); + stackSum.push(sum); + } + } + return false; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T13_PathSum.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T13_PathSum.java new file mode 100644 index 0000000..d3df09a --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T13_PathSum.java @@ -0,0 +1,103 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; + +import java.util.ArrayList; +import java.util.List; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-10 11:52 + *@Description: + * TODO 二刷力扣113题 路径总和II: + * 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 + * 叶子节点 是指没有子节点的节点。 + *@Version: 1.0 + */ +public class T13_PathSum { + + List cur=new ArrayList<>(); + List> result=new ArrayList<>(); + + /** + * 递归法: + * 速度击败99.98%,内存击败88.17% + * @param root + * @param targetSum + * @return + */ + public List> pathSum(TreeNode root, int targetSum) { + travel(root,targetSum); + return result; + + } + public void travel(TreeNode node, int targetSum){ + if(node==null){ + return; + } + cur.add(node.val); + if(node.left==null&&node.right==null){ + //到达叶子节点 + if(node.val==targetSum){ + result.add(new ArrayList<>(cur)); + } + } + travel(node.left,targetSum- node.val); + travel(node.right,targetSum- node.val); + cur.remove(cur.size()-1); + } + + + /** + * 官方最快:思路一样,可能快在使用数组进行增减 + */ + private List> ans = new ArrayList<>(); + + private void dfs(TreeNode root, int targetSum, int current, int[] node, int index) { + if( root == null ) { + return; + } + + node[index] = root.val; + current += root.val; + if( root.left == null && root.right == null ) { + if( current == targetSum ) { + List result = new ArrayList<>(); + for( int i = 0; i <= index; i++ ) { + result.add(node[i]); + } + ans.add(result); + } + return; + } + + + dfs(root.left, targetSum, current, node, index + 1); + dfs(root.right, targetSum, current, node, index + 1); + + } + + private int getDepth(TreeNode root) { + if( root == null ) { + return 0; + } + if( root.left == null && root.right == null ) { + return 1; + } + + return Math.max(getDepth(root.left), getDepth(root.right)) + 1; + } + + public List> pathSum1(TreeNode root, int targetSum) { + int depth = getDepth(root); + if( root == null ) { + return ans; + } + + int[] node = new int[depth]; + dfs(root, targetSum, 0, node, 0); + return ans; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T14_BuildTree.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T14_BuildTree.java new file mode 100644 index 0000000..5b9a1ef --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T14_BuildTree.java @@ -0,0 +1,83 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; +import org.junit.Test; + +import java.util.Arrays; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-10 12:18 + *@Description: + * TODO 二刷力扣106题 从中序与后序遍历序列构造二叉树: + * 给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, + * postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。 + *@Version: 1.0 + */ +public class T14_BuildTree { + + @Test + public void test(){ + int[] inorder = {9, 3, 15, 20, 7}, postorder = {9, 15, 7, 20, 3}; + System.out.println(buildTree1(inorder,postorder)); + } + + /** + * 思路:后续遍历的最后一个就是根节点,以此划分左右树, + * 自己被卡在就算划分了左右但是不知道inorder和postOrder应该怎么划分; + * 事实上两个个order一定一样长,可以根据中序定边界,从而划分两边 + * 下属写法是最容易理解的写法,还有一些较为难理解但是传递索引而不是复制的写法来处理的写法,会比这个快 + * 速度击败13.81%,内存击败15.72% 6ms + * @param inorder + * @param postorder + * @return + */ + public TreeNode buildTree(int[] inorder, int[] postorder) { + int length = postorder.length; + if(length==0){ + return null; + } + TreeNode root = new TreeNode(postorder[length - 1]); + int boundary=0; + for (; boundary < inorder.length; boundary++) { + if(inorder[boundary]==postorder[length-1]){ + break; + } + } + int[] leftInorder = Arrays.copyOfRange(inorder, 0, boundary); + int[] rightInorder = Arrays.copyOfRange(inorder, boundary+1, length); + int[] leftPostorder = Arrays.copyOfRange(postorder, 0, boundary); + int[] rightPostorder = Arrays.copyOfRange(postorder, boundary, length - 1); + root.left=buildTree(leftInorder,leftPostorder); + root.right=buildTree(rightInorder,rightPostorder); + + return root; + + } + + + /** + * 官方最快 + * 速度击败100%,内存击败72.96% + */ + int post,in; + public TreeNode buildTree1(int[] inorder, int[] postorder) { + post=inorder.length-1; + in=inorder.length-1; + return buildTreeHelper(inorder,postorder,Integer.MAX_VALUE); + } + public TreeNode buildTreeHelper(int[] inorder, int[] postorder, int stop) { + if(post==-1)return null; + if(inorder[in]==stop){//stop是right边界,如果触及了右边界就那边就没有值了 + in--; + return null;//找到了右边的边界 + } + int root_val=postorder[post--]; + TreeNode root = new TreeNode(root_val); + root.right=buildTreeHelper(inorder,postorder,root_val); + root.left=buildTreeHelper(inorder,postorder,stop); + return root; + } +}