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

 题目与题解

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

题目链接:235. 二叉搜索树的最近公共祖先

代码随想录题解:​​​​​​​235. 二叉搜索树的最近公共祖先

视频讲解:二叉搜索树找祖先就有点不一样了!| 235. 二叉搜索树的最近公共祖先_哔哩哔哩_bilibili

解题思路:

        有了昨天的二叉树公共祖先的例子,今天这道题就容易很多,并且针对二叉搜索树可以做一些剪枝处理。

        同样用递归来做,入参是root和要搜索的节点pq,返回值是当前的公共祖先,终止条件为root等于p或q或root为空(因为一旦p或q等于root,说明它们一方必然是另一方的祖先;如果root为空,说明p和q在root子树中都不存在)。递归体为:如果p和q值都小于root,那就继续将左子树作为root调用递归函数;如果p和q值都大于root,就将右子树作为root调用递归函数;否则p和q必然分别在左右子树中,此时root就是当前最近公共祖先。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (p == root || q == root || root == null) return root;
		if (p.val < root.val && q.val < root.val)
			return lowestCommonAncestor(root.left, p, q);
		else if (p.val > root.val && q.val > root.val)
			return lowestCommonAncestor(root.right, p, q);
		else
			return root;
    }
}

看完代码随想录之后的想法 

        因为二叉搜索树是有顺序的,所以迭代也很好做,跟递归思路类似,更好写一点。

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        while(root) {
            if (root->val > p->val && root->val > q->val) {
                root = root->left;
            } else if (root->val < p->val && root->val < q->val) {
                root = root->right;
            } else return root;
        }
        return NULL;
    }
};

遇到的困难

        有前面的题目打底,这道很容易。

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

题目链接:701.二叉搜索树中的插入操作

代码随想录题解:​​​​​​​701.二叉搜索树中的插入操作

视频讲解:原来这么简单? | LeetCode:701.二叉搜索树中的插入操作_哔哩哔哩_bilibili

解题思路:

        因为二叉搜索树是有顺序的,所以最简单的做法就是作为叶子节点插入,这样不用更改其他任何节点的结构,挂在某一个有空位的节点下面就好。

        这里用递归的写法,入参就是根节点和要插入的节点,终止条件是当前节点为空,就直接return新节点,返回值是插入后的root节点;递归体为:如果当前节点为空返回新节点,如果当前节点值大于插入值,则继续将左子树作为根结点调用递归函数,小于则用右子树调用递归函数。

class Solution {
    public TreeNode insertIntoBST(TreeNode root, int val) {
		if (root == null) return new TreeNode(val);
		if (val < root.val) {
			if (root.left == null) root.left = new TreeNode(val);
			else insertIntoBST(root.left, val);
		} else {
			if (root.right == null) root.right = new TreeNode(val);
			else insertIntoBST(root.right, val);
		}
		return root;
    }
}

看完代码随想录之后的想法 

        二叉搜索树用迭代做也比较容易,麻烦的一点在于需要记录一下当前节点的父节点,方便后序赋值。遍历方法为,当前节点不为空时,将parent节点记录为当前节点,如果新的值小于当前节点,使当前节点向左搜索,否则向右搜索。遍历结束后,就会得到应当添加叶子节点的父节点位置,然后再根据该父节点与新节点的值大小,相应添加到左或者右子树上。

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == NULL) {
            TreeNode* node = new TreeNode(val);
            return node;
        }
        TreeNode* cur = root;
        TreeNode* parent = root; // 这个很重要,需要记录上一个节点,否则无法赋值新节点
        while (cur != NULL) {
            parent = cur;
            if (cur->val > val) cur = cur->left;
            else cur = cur->right;
        }
        TreeNode* node = new TreeNode(val);
        if (val < parent->val) parent->left = node;// 此时是用parent节点的进行赋值
        else parent->right = node;
        return root;
    }
};

遇到的困难

        无

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

题目链接:​​​​​​​450.删除二叉搜索树中的节点 

代码随想录题解:450.删除二叉搜索树中的节点 

视频讲解:调整二叉树的结构最难!| LeetCode:450.删除二叉搜索树中的节点_哔哩哔哩_bilibili

解题思路:

        删除节点与添加节点相比,复杂的地方在于,删除的很可能不是叶子节点,此时就需要调整二叉树的结构,容易出错。

        这里还是用递归的方法,入参是root和要删除的值val,终止条件是root为空或root的值等于val,返回值是经过完成删除后的root,递归体较为复杂,如果root值不等于val,则根据val与root的大小,递归用root的左子树或右子树作为入参继续删除;如果root等于val,要分情况讨论:

  • 如果root是叶子结点,直接返回null
  • 如果root左子树为空,则直接让root等于右子树并返回
  • 如果root右子树为空,则直接让root等于左子树并返回
  • 如果两个子树都不为空,将左子树挂到右子树最左边的叶子结点左边,然后将root等于右子树并返回
class Solution {
    public TreeNode deleteNode(TreeNode root, int key) {
		if (root == null) return root;
		if (root.val == key) {
			if (root.left == null && root.right == null) {
				return null;
			} else if (root.right != null && root.left == null){
				return root.right;
			} else if (root.right == null && root.left != null){
				return root.left;
			} else {
				TreeNode cur = root.right;
				while (cur.left != null) cur = cur.left;
				cur.left = root.left;
				return root.right;
			}
		} else {
			if (key < root.val) root.left = deleteNode(root.left, key);
			else root.right = deleteNode(root.right, key);
		}
		return root;
    }
}

看完代码随想录之后的想法 

        一开始的时候没有完全做对,因为忽略了左右子树都存在这种情况,看了随想录的第五种情况才理解,动图还是很不错的。

遇到的困难

        root值等于val时,最后一个尤其难理解,我自己写的时候就是没有想到这种情况该怎么处理,所以对于[50,30,70,null,40,60,80],删除节点为50的例子就出错了,因为如果不做转移左子树的操作,在60比70小的情况下,直接让root等于70这个节点,会导致二叉搜索树右子树存在小于根节点的值,与定义相悖了。所以这里需要处理一下,保证结构改变以后也符合二叉搜索树的定义。

今日收获

        继续巩固了一下二叉树里面的常用递归操作,学习了如何在二叉搜索树里面增删节点。感觉方法有点万变不离其宗的意思,希望实际面试的时候能写出来。

  • 10
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值