Leetcode 450.删除二叉搜索树中的节点(最好理解的版本)
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点; 如果找到了,删除它。 说明: 要求算法时间复杂度为 O(h),h 为树的高度。
示例:
解题思路:
递归
- 确定递归函数参数以及返回值
代码如下:
public TreeNode deleteNode(TreeNode root, int key)
- 确定终止条件
遇到空返回,其实这也说明没找到删除的节点,遍历到空节点直接返回了
if (root == null) return root;
- 确定单层递归的逻辑
这里就把二叉搜索树中删除节点遇到的情况都搞清楚。
有以下五种情况:
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回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;
}
}
代码跟踪:
假设我们有以下二叉搜索树:
5
/ \
3 6
/ \ \
2 4 7
我们要删除节点 3。根据代码的逻辑,我们首先检查根节点 5 的值是否等于目标值 3,如果是,则进行删除操作。
由于节点 3 有左子树和右子树,我们需要找到右子树中的最小节点来替换要删除的节点。在这个例子中,右子树的最小节点是节点 4。
首先,我们找到节点 4,然后将节点 4 的左子树连接到节点 4 的父节点 5 的左侧,得到以下结果:
5
/ \
4 6
/ \
2 7
接下来,我们将节点 5 的右子树作为新的根节点,得到以下结果:
6
/ \
4 7
/
2
这样,我们成功地从二叉搜索树中删除了节点 3,并保持了二叉搜索树的性质。
评论区