大家好,我是吴师兄。
众所周知,人生如戏全靠演技,出门在外,咱们靠的都是一个“人设”,面试就是展示自己人设的一个场景,从面试进门的那个时刻起,我们就开始了职场“表演”,有的人想把自己塑造成技术高手,有的人想打造工作干练的形象。
而有的人却选择了反向操作。
一位参加字节面试的同学面对熟悉的问题时,不直接给出答案,而是展现出层层思考、逐步优化的过程,这个操作确实容易让面试官参与进来进而加深其印象。
演技很好,可惜却被面试官识破。
所以如果字节面试过程中如果遇到下方这种简单且熟悉的题目,最好秒解。
题目描述是这样的,给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
1、首先找到需要删除的节点;
2、如果找到了,删除它。
二叉搜索树(BST)是一种特殊的二叉树,对于任意节点,其左子树中的所有节点的值都小于该节点的值,右子树中的所有节点的值都大于该节点的值。
这个性质使得二叉搜索树在查找、插入和删除操作上有很好的性能。
当需要在二叉搜索树中删除一个节点时,我们需要考虑以下几种情况:
null
或原节点。deleteNode(TreeNode root, int key)
方法是主要的逻辑实现,它递归地在二叉树中查找并删除指定值的节点。
如果找到了需要删除的节点 root.val == key
,根据上面的情况进行处理:
findMinNode(TreeNode node)
方法),用这个最小节点的值替换当前节点的值,然后删除右子树中的这个最小节点。findMinNode(TreeNode node)
方法用于找到以 node
为根的子树中的最小值节点。由于二叉搜索树的性质,这个最小值节点肯定在最左边,因此通过不断访问左子节点直到 null
即可找到最小值节点。通过这种方式,可以有效地在二叉搜索树中删除任意一个节点,同时保持二叉搜索树的性质不变。
代码如下:
// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 删除二叉搜索树中的节点( LeetCode 450 ):https://leetcode-cn.com/problems/delete-node-in-a-bst/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
// 1、如果 root 为空,那么直接返回空
if (root == null) return null;
// 2、如果 root 的节点值等于需要删除的值,那么需要根据以下几种情况进行处理
if (root.val == key) {
// 情况 1:当前节点的左子树为空,那么当前节点 root 由 root 的右子树占位就行
// 比如 key 为 7
// 6
// / \
// 2 7
// \
// 8
// 直接将以 8 作为根节点的二叉树挪到 7 的位置
// 6
// / \
// 2 8
if (root.left == null) return root.right;
// 情况 2:当前节点的右子树为空,那么当前节点 root 由 root 的左子树占位就行
// 比如 key 为 2
// 6
// / \
// 2 7
// /
// 1
// 直接将以 1 作为根节点的二叉树挪到 2 的位置
// 6
// / \
// 1 7
if (root.right == null) return root.left;
// 情况 3:被删除节点既有左子树,又有右子树
// 比如 key 为 2
// 5
// / \
// 2 6
// / \ \
// 1 4 7
// /
// 3
// 需要找到右子树最小的值,或者左子树中最大的值
// 这里我们去找右子树最小的值,为 3
TreeNode minNodeOfRight = findMinNode(root.right);
// 找到右子树最小的值之后,修改当前节点 root 的值为右子树最小的值
root.val = minNodeOfRight.val;
// 同时,记得删除掉 root 的右子树最小的值之
// 删除操作就是以 root 作为根节点,key 为右子树最小的值进行删除
root.right = deleteNode(root.right, minNodeOfRight.val);
// 3、如果 root 的节点值小于需要删除的值,那么就在 root 的右子树中去查找
} else if (root.val < key) {
// 在 root 的右子树中去查找并删除 key
root.right = deleteNode(root.right, key);
// 4、如果 root 的节点值大于需要删除的值,那么就在 root 的左子树中去查找
} else if (root.val > key) {
// 在 root 的左子树中去查找并删除 key
root.left = deleteNode(root.left, key);
}
// 最后返回需要已经删除了 key 的二叉树的根节点
return root;
}
// 通过 findMinNode ,可以找到二叉搜索树中最小的元素
private TreeNode findMinNode(TreeNode node) {
// 由于二叉搜索树,左子树所有元素的值都小于根节点的值
// 所以可以不断的查找,直到为叶子节点,那么就找到了
while (node.left != null) {
// 不断的去查找当前节点的左子树
node = node.left;
}
// 返回当前二叉搜索树中最小的元素
return node;
}
}