From 3524d0c2a9b126be7601390ef1e39025ffdefd0f Mon Sep 17 00:00:00 2001 From: markilue <745518019@qq.com> Date: Sun, 29 Jan 2023 14:55:39 +0800 Subject: [PATCH] =?UTF-8?q?leecode=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...tor.java => T20_LowestCommonAncestor.java} | 2 +- ...I.java => T21_LowestCommonAncestorII.java} | 2 +- ...ertIntoBST.java => T22_InsertIntoBST.java} | 2 +- .../{DeleteNode.java => T23_DeleteNode.java} | 2 +- .../tree/second/T20_LowestCommonAncestor.java | 66 ++++++++++ .../second/T21_LowestCommonAncestorII.java | 113 ++++++++++++++++++ .../tree/second/T22_InsertIntoBST.java | 63 ++++++++++ .../leecode/tree/second/T23_DeleteNode.java | 80 +++++++++++++ 8 files changed, 326 insertions(+), 4 deletions(-) rename Leecode/src/main/java/com/markilue/leecode/tree/{LowestCommonAncestor.java => T20_LowestCommonAncestor.java} (99%) rename Leecode/src/main/java/com/markilue/leecode/tree/{LowestCommonAncestorII.java => T21_LowestCommonAncestorII.java} (98%) rename Leecode/src/main/java/com/markilue/leecode/tree/{InsertIntoBST.java => T22_InsertIntoBST.java} (99%) rename Leecode/src/main/java/com/markilue/leecode/tree/{DeleteNode.java => T23_DeleteNode.java} (98%) create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/second/T20_LowestCommonAncestor.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/second/T21_LowestCommonAncestorII.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/second/T22_InsertIntoBST.java create mode 100644 Leecode/src/main/java/com/markilue/leecode/tree/second/T23_DeleteNode.java diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestor.java b/Leecode/src/main/java/com/markilue/leecode/tree/T20_LowestCommonAncestor.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestor.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T20_LowestCommonAncestor.java index 8847c3c..4b54c55 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestor.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T20_LowestCommonAncestor.java @@ -18,7 +18,7 @@ import java.util.Set; * “对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” * @Version: 1.0 */ -public class LowestCommonAncestor { +public class T20_LowestCommonAncestor { @Test public void test() { diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestorII.java b/Leecode/src/main/java/com/markilue/leecode/tree/T21_LowestCommonAncestorII.java similarity index 98% rename from Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestorII.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T21_LowestCommonAncestorII.java index b6be9fb..0051edb 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/LowestCommonAncestorII.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T21_LowestCommonAncestorII.java @@ -13,7 +13,7 @@ import org.junit.Test; * “对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” * @Version: 1.0 */ -public class LowestCommonAncestorII { +public class T21_LowestCommonAncestorII { @Test public void test(){ diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/InsertIntoBST.java b/Leecode/src/main/java/com/markilue/leecode/tree/T22_InsertIntoBST.java similarity index 99% rename from Leecode/src/main/java/com/markilue/leecode/tree/InsertIntoBST.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T22_InsertIntoBST.java index 25c4384..f7da432 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/InsertIntoBST.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T22_InsertIntoBST.java @@ -17,7 +17,7 @@ import java.util.List; * * @Version: 1.0 */ -public class InsertIntoBST { +public class T22_InsertIntoBST { @Test public void test(){ diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java b/Leecode/src/main/java/com/markilue/leecode/tree/T23_DeleteNode.java similarity index 98% rename from Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java rename to Leecode/src/main/java/com/markilue/leecode/tree/T23_DeleteNode.java index c2251b0..5e6a2ee 100644 --- a/Leecode/src/main/java/com/markilue/leecode/tree/DeleteNode.java +++ b/Leecode/src/main/java/com/markilue/leecode/tree/T23_DeleteNode.java @@ -9,7 +9,7 @@ import static com.markilue.leecode.tree.T03_InorderTraversal.inorderTraversal1; /** * 删除二叉排序树的某个节点 */ -public class DeleteNode { +public class T23_DeleteNode { public static void main(String[] args) { diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T20_LowestCommonAncestor.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T20_LowestCommonAncestor.java new file mode 100644 index 0000000..d9c8093 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T20_LowestCommonAncestor.java @@ -0,0 +1,66 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-29 10:08 + *@Description: + * TODO 二刷力扣236题 二叉树的最近公共祖先: + * 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。 + * 百度百科中最近公共祖先的定义为: + * “对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x, + * 满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + * + *@Version: 1.0 + */ +public class T20_LowestCommonAncestor { + + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) { + return root; + } + //这里之所以可以直接返回,而不怕其子树中有另一个节点, + // 是因为后面如果都不满足会直接返回root,如果root里面有子树,那么root也是最近祖先 + if(root.val==p.val||root.val==q.val){ + return root; + } + TreeNode node = lowestCommonAncestor(root.left, p, q); + TreeNode node1 = lowestCommonAncestor(root.right, p, q); + if (node == null) { + return node1; + } else if (node1 == null) { + return node; + } else if (node.val == p.val && node1.val == q.val || node.val == q.val && node1.val == p.val) { + //这个判断条件可以优化为left和right都不等于null,就可以返回root + return root; + } + + return root; + + + } + + + /** + * 官方最快 + * 5ms + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) return root; + TreeNode left = lowestCommonAncestor1(root.left, p, q); + TreeNode right = lowestCommonAncestor1(root.right, p, q); + if (left != null && right != null) {return root;} + return left != null ? left : right; + + } + + +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T21_LowestCommonAncestorII.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T21_LowestCommonAncestorII.java new file mode 100644 index 0000000..f112898 --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T21_LowestCommonAncestorII.java @@ -0,0 +1,113 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-29 10:52 + *@Description: + * TODO 二刷力扣235题 二叉搜索树的最近公共祖先: + * 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 + * 百度百科中最近公共祖先的定义为: + * “对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” + * 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5] + *@Version: 1.0 + */ +public class T21_LowestCommonAncestorII { + + /** + * 思路:理论上来说,适用于普通二叉树的方式,也适用于二叉搜索树 + * 速度击败35.59%,内存击败19.97% + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if(root==null|| root.val==p.val||root.val==q.val)return root; + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if(left!=null&&right!=null)return root; + return left==null?right:left; + } + + /** + * 思路:从上往下找,找到第一个在p和q中间的值,就一定是他们的公共祖先 + * 速度击败99.96%,内存击败93.11% 5ms + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor1(TreeNode root, TreeNode p, TreeNode q) { + if(root==null)return root; + if(p.val>q.val){ + TreeNode temp=p; + p=q; + q=temp; + } + if(root.val<=q.val&&root.val>=p.val){ + return root; + }else if(root.val Math.max(pv,qv)) { + if (rv < Math.min(pv, qv)) { + root = root.right; + rv = root.val; + } + else { + root = root.left; + rv = root.val; + } + } + return root; + + } + + /** + * 针对最快的改进,一直计算最大最小太麻烦了,直接存起来 + * 速度击败99.96%,内存击败59.90% 5ms + * @param root + * @param p + * @param q + * @return + */ + public TreeNode lowestCommonAncestor3(TreeNode root, TreeNode p, TreeNode q) { + int min = Math.min(p.val, q.val); + int max = Math.max(p.val, q.val); + int rv = root.val; + while ( rv < min || rv >max ) { + if (rv < min) { + root = root.right; + rv = root.val; + } + else { + root = root.left; + rv = root.val; + } + } + return root; + + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T22_InsertIntoBST.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T22_InsertIntoBST.java new file mode 100644 index 0000000..6f5283e --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T22_InsertIntoBST.java @@ -0,0 +1,63 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-29 11:19 + *@Description: + * TODO 二刷力扣701 二叉搜索树中的插入操作: + * 给定二叉搜索树(BST)的根节点 root 和要插入树中的值 value ,将值插入二叉搜索树。 + * 返回插入后二叉搜索树的根节点。 输入数据 保证 ,新值和原始二叉搜索树中的任意节点值都不同。 + * 注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回 任意有效的结果 。 + *@Version: 1.0 + */ +public class T22_InsertIntoBST { + + /** + * 思路:找到合适的位置插在叶子结点 + * 速度击败100%,内存击败11.89% + * @param root + * @param val + * @return + */ + public TreeNode insertIntoBST(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + TreeNode temp = root; + insert(root, val); + return root; + + } + + public void insert(TreeNode root, int val) { + if (root.val < val) { + if (root.right == null) root.right = new TreeNode(val); + else insertIntoBST(root.right, val); + } else { + if (root.left == null) root.left = new TreeNode(val); + else insertIntoBST(root.left, val); + } + } + + /** + * 代码随想录优秀写法 + * @param root + * @param val + * @return + */ + public TreeNode insertIntoBST1(TreeNode root, int val) { + if (root == null) // 如果当前节点为空,也就意味着val找到了合适的位置,此时创建节点直接返回。 + return new TreeNode(val); + + if (root.val < val){ + root.right = insertIntoBST(root.right, val); // 递归创建右子树 + }else if (root.val > val){ + root.left = insertIntoBST(root.left, val); // 递归创建左子树 + } + return root; + } +} diff --git a/Leecode/src/main/java/com/markilue/leecode/tree/second/T23_DeleteNode.java b/Leecode/src/main/java/com/markilue/leecode/tree/second/T23_DeleteNode.java new file mode 100644 index 0000000..821602f --- /dev/null +++ b/Leecode/src/main/java/com/markilue/leecode/tree/second/T23_DeleteNode.java @@ -0,0 +1,80 @@ +package com.markilue.leecode.tree.second; + +import com.markilue.leecode.tree.TreeNode; + +/** + *@BelongsProject: Leecode + *@BelongsPackage: com.markilue.leecode.tree.second + *@Author: dingjiawen + *@CreateTime: 2023-01-29 11:53 + *@Description: + * TODO 二刷力扣450题 删除二叉搜索树中的节点: + * 给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。 + * 一般来说,删除节点可分为两个步骤: + * 首先找到需要删除的节点; + * 如果找到了,删除它。 + *@Version: 1.0 + */ +public class T23_DeleteNode { + + /** + * 核心思路:找到需要删除的节点,然后寻找其左子树的最右节点或右子树的最左节点,将其赋值给当前节点; + * 然后变为删除这个最左右节点(该节点最多只有一个子树) + * 速度击败100%,内存击败41.24% + * @param root + * @param key + * @return + */ + public TreeNode deleteNode(TreeNode root, int key) { + if (root == null) { + return root; + } + TreeNode temp = root; + + + TreeNode pre = null;//父节点 + //寻找需要删除的节点 + while (temp != null && temp.val != key) { + pre = temp; + if (temp.val > key) { + temp = temp.left; + } else { + temp = temp.right; + } + } + if(temp==null){ + //没找到 + return root; + } + + //寻找要删除节点其右子树的最左节点 + TreeNode need=null; + if (temp.right != null) { + pre = temp; + need = temp.right; + while (need.left != null) { + pre = need; + need = need.left; + } + temp.val = need.val; + }else { + need=temp; + } + + //后续删除need节点;need最多仅有一个节点 + TreeNode child = need.left == null ? need.right : need.left; + if (pre == null) { + //删除的是root节点 + return child; + } + + + if(pre.left==need){ + pre.left=child; + }else { + pre.right=child; + } + + return root; + } +}