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

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

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 代码

//
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 代码

//
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 代码

//
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;
  }
}
相关文章
|
2月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
45 0
|
1月前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
2月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
31 2
|
2月前
【LeetCode 44】235.二叉搜索树的最近公共祖先
【LeetCode 44】235.二叉搜索树的最近公共祖先
20 1
|
2月前
LeetCode第二十四题(两两交换链表中的节点)
这篇文章介绍了LeetCode第24题的解法,即如何通过使用三个指针(preNode, curNode, curNextNode)来两两交换链表中的节点,并提供了详细的代码实现。
28 0
LeetCode第二十四题(两两交换链表中的节点)
|
2月前
Leetcode第十九题(删除链表的倒数第N个节点)
LeetCode第19题要求删除链表的倒数第N个节点,可以通过快慢指针法在一次遍历中实现。
47 0
Leetcode第十九题(删除链表的倒数第N个节点)
|
2月前
【LeetCode 46】450.删除二叉搜索树的节点
【LeetCode 46】450.删除二叉搜索树的节点
21 0
|
2月前
【LeetCode 43】236.二叉树的最近公共祖先
【LeetCode 43】236.二叉树的最近公共祖先
21 0
|
4月前
|
算法
LeetCode第24题两两交换链表中的节点
这篇文章介绍了LeetCode第24题"两两交换链表中的节点"的解题方法,通过使用虚拟节点和前驱节点技巧,实现了链表中相邻节点的交换。
LeetCode第24题两两交换链表中的节点
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行