代码随想录算法训练营第二十一天 | LeetCode 235. 二叉搜索树的最近公共祖先、701. 二叉搜索树中的插入操作、450. 删除二叉搜索树中的节点

代码随想录算法训练营第二十一天 | LeetCode 235. 二叉搜索树的最近公共祖先、701. 二叉搜索树中的插入操作、450. 删除二叉搜索树中的节点

文章链接:二叉搜索树的最近公共祖先 二叉搜索树的插入操作 删除二叉搜索树中的节点

视频链接:二叉搜索树的最近公共祖先 二叉搜索树的插入操作 删除二叉搜索树中的节点

目录

[代码随想录算法训练营第二十一天 | LeetCode 235. 二叉搜索树的最近公共祖先、701. 二叉搜索树中的插入操作、450. 删除二叉搜索树中的节点](#代码随想录算法训练营第二十一天 | LeetCode 235. 二叉搜索树的最近公共祖先、701. 二叉搜索树中的插入操作、450. 删除二叉搜索树中的节点)

[1. LeetCode 235. 二叉搜索树的最近公共祖先](#1. LeetCode 235. 二叉搜索树的最近公共祖先)

[1.1 思路](#1.1 思路)

[1.2 代码](#1.2 代码)

[2. LeetCode 701. 二叉搜索树中的插入操作](#2. LeetCode 701. 二叉搜索树中的插入操作)

[2.1 思路](#2.1 思路)

[2.2 代码](#2.2 代码)

[3. LeetCode 450. 删除二叉搜索树中的节点](#3. LeetCode 450. 删除二叉搜索树中的节点)

[3.1 思路](#3.1 思路)

[3.2 代码](#3.2 代码)


1. LeetCode 235. 二叉搜索树的最近公共祖先

1.1 思路

  1. 在普通二叉树中搜索最近公共祖先是用了后序遍历,然后一层一层返回。本题是二叉搜索树,可以利用它的特性,如果p和q都比根节点小,那说明最近公共祖先一定在左子树。如果p和q都比根节点大,那说明最近公共祖先一定在右子树。那找到了一个节点在p和q之间,那就是公共节点了,并且一定是最近的了,因为是二叉树,再往下不管是左还是右都分开了
  2. 递归函数的参数和返回值:返回值就是节点,参数就是root,p,q。都是题目的
  3. 终止条件:遇到空就返回空
  4. 单层递归的逻辑:因为这题本来就是有序的,而且不涉及中间节点的处理,就不管前中后序了,只需要有左和右即可。如果root比p和q的都大,就向左搜索,left=travelsal(root.left, p, q),如果left不为空就说明left就是最近公共祖先了,就返回left。如果root比p和q的都小,就向右搜索,right=travelsal(root.right, p, q),如果right不为空就说明right就是最近公共祖先了,就返回right。剩下的情况就是最近公共祖先root在p和q之间了,就直接return root。

1.2 代码

java 复制代码
//
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null){
            return root;
        }
        if(root.val>p.val&&root.val>q.val){
            TreeNode left=lowestCommonAncestor(root.left,p,q);
            if(left!=null){
                return left;
            }
        }
        if(root.val<p.val&&root.val<q.val){
            TreeNode right=lowestCommonAncestor(root.right,p,q);
            if(right!=null){
                return right;
            }
        }
        return root;
    }
}

2. LeetCode 701. 二叉搜索树中的插入操作

2.1 思路

  1. 在二叉搜索树中插入任何一个节点的话,在叶子节点都能找到它的位置。所以是找到一个叶子节点插入即可,依然保持二叉树的有序性
  2. 递归函数的参数和返回值:返回值节点node,参数就是root,val
  3. 终止条件:如果遇到空,就找到插入节点的位置了,就是叶子节点了。就创建节点node然后放入val,然后返回node。因为是一层一层向下遍历,返回的时候就是把节点返回给上面遍历下来的那个节点
  4. 单层递归的逻辑:如果节点值比val大,就向左遍历,就用root.left接收函数(root.left, val)的返回值,作为root的左孩子。如果节点值比val小,就向右遍历,就用root.right接收函数(root.right, val)的返回值,作为root的右孩子。举例这里如果递归到了最后一层的叶子节点,叶子节点插入的新节点就返回给此时的root,root就作为新节点的父节点,二叉树就连接起来了。最后return root;就是一层一层返回给最终新的二叉树的根节点了。

2.2 代码

java 复制代码
//
class Solution {
    public TreeNode insertIntoBST(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;
    }
}

3. LeetCode 450. 删除二叉搜索树中的节点

3.1 思路

  1. 这题要求删除节点后依然保证仍是一棵二叉搜索树
  2. 先分析有什么情况:①没找到要删的节点;其余四种情况就是找到了要删的节点②要删除的节点左右都为空,即这个节点是叶子节点;③这个节点不是叶子节点,左不为空右为空,就直接让其左孩子变为其父节点的左孩子;④这个节点不是叶子节点,左为空右不为空,就直接让其右孩子变为其父节点的右孩子;⑤左不为空右也不为空,这种情况需要大幅调整结构了。删除这个节点后要么就是让左孩子继位,要么就是让右孩子继位,举例假设让右孩子继位,左孩子就只能放在原右孩子的左子树中最左侧的位置(这个数是仅仅比被删节点大一点点的,就刚刚能让原左孩子作为这个节点的左孩子,这里可能不好理解,看视频的6分钟左右),放完以后,在删除节点以后,直接让被删除节点的父节点指向右孩子
  3. 递归函数的返回值和参数:定义函数就是原题的函数,返回的是新的二叉搜索树的根节点
  4. 终止条件:遍历找到要删除的节点。因为这题不需要遍历整棵二叉树,重点在删除节点的逻辑,因此删除的操作是放在终止条件中。
  5. 第1种情况,就是遍历到空了也没找到,就返回null;
  6. 第2种情况,是叶子节点(左右都为空),就直接return null,这个null是由原节点的父节点接收,因为在代码最下面会有当前层的左子树=下一层递归的返回值以及右子树=下一层递归的返回值;
  7. 第3种情况,左不为空右为空,就让被删节点的父节点接收其左孩子,就是返回root.left,被删节点的父节点会接收住的
  8. 第4种情况,左为空右不为空,就让被删节点的父节点接收其右孩子,就是返回root.right,被删节点的父节点会接收住的
  9. 第5种情况就else了,(已上面的例子以右孩子继位为例)先找到被删节点的右子树的最左侧的值,只有这个数是仅仅比被删节点大一点点的,(这里已经遍历到了被删节点)首先定义个cur=root.right,然后向左遍历去到叶子节点,while(cur.left!=null) cur=cur.left;然后让cur.left=root.left,即这个叶子节点的左子树等于被删节点的左子树了。然后就是删除那个节点了,此时的处理逻辑就是左为空右不为空(第4种情况)的处理逻辑了,就return root.right。如果是让左孩子继位就可以自己画图看看
  10. 单层递归的逻辑:如果key<root.val就向左遍历搜索,root.left=delete(root.left, val);如果key>root.val就向右遍历搜索,root.right=delete(root.right, val);这里用节点的左右孩子接收的就是删除节点后返回的节点。最后左右子树处理完了就return root

3.2 代码

java 复制代码
//
class Solution {
  public TreeNode deleteNode(TreeNode root, int key) {
    if (root == null) return root;
    if (root.val == key) {
      if (root.left == null) {
        return root.right;
      } else if (root.right == null) {
        return root.left;
      } else {
        TreeNode cur = root.right;
        while (cur.left != null) {
          cur = cur.left;
        }
        cur.left = root.left;
        root = root.right;
        return root;
      }
    }
    if (root.val > key) root.left = deleteNode(root.left, key);
    if (root.val < key) root.right = deleteNode(root.right, key);
    return root;
  }
}
相关推荐
tinker在coding6 分钟前
Coding Caprice - Linked-List 1
算法·leetcode
LCG元3 小时前
【面试问题】JIT 是什么?和 JVM 什么关系?
面试·职场和发展
XH华4 小时前
初识C语言之二维数组(下)
c语言·算法
南宫生5 小时前
力扣-图论-17【算法学习day.67】
java·学习·算法·leetcode·图论
不想当程序猿_5 小时前
【蓝桥杯每日一题】求和——前缀和
算法·前缀和·蓝桥杯
落魄君子5 小时前
GA-BP分类-遗传算法(Genetic Algorithm)和反向传播算法(Backpropagation)
算法·分类·数据挖掘
菜鸡中的奋斗鸡→挣扎鸡5 小时前
滑动窗口 + 算法复习
数据结构·算法
Lenyiin5 小时前
第146场双周赛:统计符合条件长度为3的子数组数目、统计异或值为给定值的路径数目、判断网格图能否被切割成块、唯一中间众数子序列 Ⅰ
c++·算法·leetcode·周赛·lenyiin
郭wes代码6 小时前
Cmd命令大全(万字详细版)
python·算法·小程序
scan7246 小时前
LILAC采样算法
人工智能·算法·机器学习