首页 > 编程语言 >代码随想录算法Day22 | 235. 二叉搜索树的最近公共祖先 ,701.二叉搜索树中的插入操作 ,450.删除二叉搜索树中的节点

代码随想录算法Day22 | 235. 二叉搜索树的最近公共祖先 ,701.二叉搜索树中的插入操作 ,450.删除二叉搜索树中的节点

时间:2023-02-23 01:55:06浏览次数:55  
标签:right TreeNode val root 二叉 搜索 树中 节点 left

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

题目链接:235. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

思路

本题可以利用二叉搜索树 有序 的特性。

在有序树里,如果判断一个节点的左子树里有p,右子树里有q呢?

因为是有序树,所有 如果 中间节点是 q 和 p 的公共祖先,那么 中节点的数组 一定是在 [p, q]区间的。即 中节点 > p && 中节点 < q 或者 中节点 > q && 中节点 < p。

那么只要从上到下去遍历,遇到 cur节点是数值在[p, q]区间中则一定可以说明该节点cur就是q 和 p的公共祖先。

本题也不涉及到遍历顺序,因为二叉树有序,也不需要对二叉树进行处理,只需要有左和右遍历就行了。

代码

1 //递归法
2 class Solution {
3     public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
4         if (root.val > p.val && root.val > q.val) return lowestCommonAncestor(root.left, p, q);
5         if (root.val < p.val && root.val < q.val) return lowestCommonAncestor(root.right, p, q);
6         return root;
7     }
8 }
 1 //迭代法
 2 class Solution {
 3     public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
 4         while (true) {
 5             if (root.val > p.val && root.val > q.val) {
 6                 root = root.left;
 7             } else if (root.val < p.val && root.val < q.val) {
 8                 root = root.right;
 9             } else {
10                 break;
11             }
12         }
13         return root;
14     }
15 }

总结

利用好二叉搜索树的性质,因为他的有序性,递归的时候没有中结点的处理逻辑,迭代的时候也是一步到位。

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

题目链接:701. 二叉搜索树中的插入操作 - 力扣(LeetCode)

思路

这道题可以不考虑题目中提示所说的改变树的结构的插入方式,只要按照二叉搜索树的规则去遍历,遇到空节点就插入节点就可以了

代码

//递归法
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;
    }
}
 1 //迭代法
 2 class Solution {
 3     public TreeNode insertIntoBST(TreeNode root, int val) {
 4         if (root == null) return new TreeNode(val);
 5         TreeNode newRoot = root;
 6         TreeNode pre = root;
 7         while (root != null) {
 8             pre = root;
 9             if (root.val > val) {
10                 root = root.left;
11             } else if (root.val < val) {
12                 root = root.right;
13             } 
14         }
15         if (pre.val > val) {
16             pre.left = new TreeNode(val);
17         } else {
18             pre.right = new TreeNode(val);
19         }
20 
21         return newRoot;
22     }
23 }

 

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

题目链接:450. 删除二叉搜索树中的节点 - 力扣(LeetCode)

思路

这道题首先把二叉搜索树中删除节点遇到的情况都搞清楚。

有以下五种情况:

  • 第一种情况:没找到删除的节点,遍历到空节点直接返回了
  • 找到删除的节点
    • 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
    • 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
    • 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
    • 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的 右子树 的 最左面节点 的左孩子上,返回删除节点右孩子为新的根节点。

代码

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;
  }
}

通用的二叉树删除结点方式

没有使用搜索树的特性,遍历整棵树,用交换值的操作来删除目标节点。

代码中目标节点(要删除的节点)被操作了两次:

  • 第一次是和目标节点的右子树最左面节点交换。
  • 第二次直接被NULL覆盖了。

删除操作代码如下:

 1 if (root.val = key){
 2     if (root.left == null) return right;
 3     if (root.right == null) return left;
 4     // 以往右为例
 5     TreeNode node = root.right;
 6     while (node.right != null){
 7         node = node.right;
 8     }
 9     // (第一次) node就指向了最右边的叶子结点,再把叶子结点的值赋给该结点
10     root.val = node.val;
11     // (第二次)再继续向右搜索删除该叶子结点,且删除的是叶子结点的值
12     root.right = delete(root, node.val);
13 }

 总结

二叉搜索树递归不用分前中后序,因为他本身就可以看作是排好序的二叉树,且中序遍历的值是升序的。

在解决二叉搜索的时候,大体按以下思路操作

 1 public TreeNode traversal(TreeNode root, int key){
 2     // 1、返回逻辑
 3     if (root == null) 返回情况;
 4     // 其余的返回情况,全部列举
 5     if...
 6     if...
 7     // 2、递归逻辑      
 8         // 只用考虑左方向 -- 并接收左孩子传来的结果
 9     if (root.val > key) root.left = traversal(root.left, key); 
10         // 右方向同理
11     if (root.val < key) root.right = traversal(root.right, key);
12     // 3、最后递归函数返回值
13         // 通常返回处理好的结果root
14     return root;
15     
16 }

 

标签:right,TreeNode,val,root,二叉,搜索,树中,节点,left
From: https://www.cnblogs.com/xpp3/p/17146556.html

相关文章