Medium
题目描述
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中值为 key 的节点,并返回新的根节点(可能更新)。
删除过程可以分为两个步骤:
- 搜索要删除的节点
- 如果找到该节点,删除该节点
示例 1:
输入:root = [5,3,6,2,4,null,7], key = 3
输出:[5,4,6,2,null,null,7]
解释:给定要删除的节点值是 3,我们找到值为 3 的节点并删除它。
一个有效的答案是 [5,4,6,2,null,null,7]。
请注意,另一个有效答案是 [5,2,6,null,4,null,7],也会被接受。
示例 2:
输入:root = [5,3,6,2,4,null,7], key = 0
输出:[5,3,6,2,4,null,7]
解释:树中不存在值为 0 的节点。
示例 3:
输入:root = [], key = 0
输出:[]
提示:
- 树中节点数目的范围是 [0, 10^4]
- -10^5 <= Node.val <= 10^5
- 每个节点都有不同的值
- root 是合法的二叉搜索树
- -10^5 <= key <= 10^5
进阶: 能否在时间复杂度为 O(树的高度) 内解决?
解题思路
在二叉搜索树中删除节点是一个经典问题,需要考虑三种情况:
- 删除叶子节点:直接删除即可
- 删除只有一个子树的节点:用其子树替代该节点
- 删除有两个子树的节点:这是最复杂的情况,有两种处理方式:
- 用左子树中的最大值(前驱)替代该节点
- 用右子树中的最小值(后继)替代该节点
推荐使用递归方法,利用二叉搜索树的性质进行高效搜索。递归过程:
- 如果要删除的值小于当前节点值,递归处理左子树
- 如果要删除的值大于当前节点值,递归处理右子树
- 如果找到目标节点,根据其子树情况进行相应处理
对于有两个子树的节点,我选择用右子树的最小值替代,这样能保持BST的性质。具体做法是:
- 找到右子树中的最小值节点
- 用该最小值替换当前节点的值
- 递归删除右子树中的最小值节点
时间复杂度为O(h),其中h是树的高度,符合进阶要求。
代码实现
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (!root) return nullptr;
if (key < root->val) {
root->left = deleteNode(root->left, key);
} else if (key > root->val) {
root->right = deleteNode(root->right, key);
} else {
// 找到要删除的节点
if (!root->left) {
TreeNode* temp = root->right;
delete root;
return temp;
} else if (!root->right) {
TreeNode* temp = root->left;
delete root;
return temp;
} else {
// 有两个子树,找右子树的最小值
TreeNode* minNode = findMin(root->right);
root->val = minNode->val;
root->right = deleteNode(root->right, minNode->val);
}
}
return root;
}
private:
TreeNode* findMin(TreeNode* node) {
while (node->left) {
node = node->left;
}
return node;
}
};
class Solution:
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root:
return None
if key < root.val:
root.left = self.deleteNode(root.left, key)
elif key > root.val:
root.right = self.deleteNode(root.right, key)
else:
# 找到要删除的节点
if not root.left:
return root.right
elif not root.right:
return root.left
else:
# 有两个子树,找右子树的最小值
min_node = self.find_min(root.right)
root.val = min_node.val
root.right = self.deleteNode(root.right, min_node.val)
return root
def find_min(self, node):
while node.left:
node = node.left
return node
public class Solution {
public TreeNode DeleteNode(TreeNode root, int key) {
if (root == null) return null;
if (key < root.val) {
root.left = DeleteNode(root.left, key);
} else if (key > root.val) {
root.right = DeleteNode(root.right, key);
} else {
// 找到要删除的节点
if (root.left == null) {
return root.right;
} else if (root.right == null) {
return root.left;
} else {
// 有两个子树,找右子树的最小值
TreeNode minNode = FindMin(root.right);
root.val = minNode.val;
root.right = DeleteNode(root.right, minNode.val);
}
}
return root;
}
private TreeNode FindMin(TreeNode node) {
while (node.left != null) {
node = node.left;
}
return node;
}
}
var deleteNode = function(root, key) {
if (!root) return null;
if (key < root.val) {
root.left = deleteNode(root.left, key);
} else if (key > root.val) {
root.right = deleteNode(root.right, key);
} else {
// 找到要删除的节点
if (!root.left) {
return root.right;
} else if (!root.right) {
return root.left;
} else {
// 有两个子树,找右子树的最小值
let minNode = findMin(root.right);
root.val = minNode.val;
root.right = deleteNode(root.right, minNode.val);
}
}
return root;
};
function findMin(node) {
while (node.left) {
node = node.left;
}
return node;
}
复杂度分析
| 复杂度类型 | 数值 | 说明 |
|---|---|---|
| 时间复杂度 | O(h) | h 是树的高度,平均情况下为 O(log n),最坏情况下为 O(n) |
| 空间复杂度 | O(h) | 递归调用栈的深度,平均情况下为 O(log n),最坏情况下为 O(n) |
相关题目
- . Split BST (Medium)