给定一个二叉搜索树的根节点 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
输出: []
�
二叉树特点:
1)左子树所有的节点值都比根节点的值小
2)右子树所有的节点值都比根节点的值大
若要删除一个节点,则需要先找到这个节点,然后进行删除操作:
1)如果值比当前节点值小,则继续往左子树找
2)如果值比当前节点值大,则继续往右子树找
3)如果值等于当前节点的值,则表示找到目标节点,进行节点删除操作
�
public TreeNode deleteNode(TreeNode root, int key) {
if (root.val == key) {
// 找到目标,进行节点删除操作
}
if (key < root.val) {
// 去左子树找
root.left = deleteNode(root.left, key);
}
if (key > root.val) {
// 去右子树找
root.right = deleteNode(root.right, key);
}
return root;
}
那删除一个二叉搜索树中的节点,该怎么删除呢?怎么找到代替被删除的节点呢?
假设二叉搜索树如下:
4 4 4 4 4
/ \ / \ / \ / \ / \
2 6 ----> 2 6 2 6 2 6 2 6
/ \ / \ \ / \ / / \ / \ \ / \ /
1 3 5 7 3 5 7 1 5 7 1 3 7 1 3 5
如果需要删除的节点没有子节点-节点 1 或者 3 或者 5 或者 7,那么直接删除即可
if (root.left == null && root.right == null) {
root = null;
}
假设二叉搜索树如下:
4 4
/ \ / \
2 6 -----> 3 6
\ / \ / \
3 5 7 5 7
4 4
/ \ / \
2 6 -----> 1 6
/ / \ / \
1 5 7 5 7
如果需要删除的节点有一个子节点-节点 2 ,那么让子节点代替自己
if (root.left == null || root.right == null) {
if (root.left == null) {
root = root.right;
}
if (root.right == null) {
root = root.left;
}
}
假设二叉搜索树如下:
4
/ \
2 6
/ \ / \
1 3 5 7
如果需要删除的节点有两个子节点-节点 4 ,那么该怎么删除呢?
如果从左子树中找,则需要找到左子树中节点值最大的节点,然后让其代替被删除的节点
4 3
/ \ / \
2 6 -----> 2 6
/ \ / \ / / \
1 3 5 7 1 5 7
if (root.left != null && root.right != null) {
// 找到左子树最大的节点
TreeNode leftMaxNode = root.left;
while (leftMaxNode.right != null) {
leftMaxNode = leftMaxNode.right;
}
// 左子树删除左子树最大的节点
root.left = deleteNode(root.left, leftMaxNode.val);
// 用 leftMaxNode 代替 root
leftMaxNode.left = root.left;
leftMaxNode.right = root.right;
root = leftMaxNode;
}
如果从右子树中找,则需要找到右子树中节点值最小的节点,然后让其代替被删除的节点
4 5
/ \ / \
2 6 -----> 2 6
/ \ / \ / \ \
1 3 5 7 1 3 7
if (root.left != null && root.right != null) {
// 找到右子树最小的节点
TreeNode rightMinNode = root.right;
while (rightMinNode.left != null) {
rightMinNode = rightMinNode.left;
}
// 右子树删除右子树最小的节点
root.right = deleteNode(root.right, rightMinNode.val);
// 用 leftMaxNode 代替 root
rightMinNode.left = root.left;
rightMinNode.right = root.right;
root = rightMinNode;
}
完整算法
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return null;
}
if (root.val == key) {
// 找到目标,进行节点删除
// 如果目标节点是末子节点,直接删除即可
if (root.left == null && root.right == null) {
// 结束查找
return null;
}
// 如果目标节点有一个子节点,让子节点代替自己
if (root.left == null || root.right == null) {
if (root.left == null) {
root = root.right;
}
if (root.right == null) {
root = root.left;
}
// 结束查找
return root;
}
// 如果目标节点有两个子节点,不能直接代替,需要从左子树和右子树中选择出新的根节点
// 假设从左子树找
if (root.left != null && root.right != null) {
// 找到左子树最大的节点
TreeNode leftMaxNode = root.left;
while (leftMaxNode.right != null) {
leftMaxNode = leftMaxNode.right;
}
// 左子树删除左子树最大的节点
root.left = deleteNode(root.left, leftMaxNode.val);
// 用 leftMaxNode 代替 root
leftMaxNode.left = root.left;
leftMaxNode.right = root.right;
root = leftMaxNode;
}
}
if (key < root.val) {
// 去左子树
root.left = deleteNode(root.left, key);
}
if (key > root.val) {
// 去右子树
root.right = deleteNode(root.right, key);
}
return root;
}
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return null;
}
if (root.val == key) {
// 找到目标,进行节点删除
// 如果目标节点是末子节点,直接删除即可
if (root.left == null && root.right == null) {
// 结束查找
return null;
}
// 如果目标节点有一个子节点,让子节点代替自己
if (root.left == null || root.right == null) {
if (root.left == null) {
root = root.right;
}
if (root.right == null) {
root = root.left;
}
// 结束查找
return root;
}
// 如果目标节点有两个子节点,不能直接代替,需要从左子树和右子树中选择出新的根节点
// 假设从右子树找
if (root.left != null && root.right != null) {
// 找到右子树最小的节点
TreeNode rightMinNode = root.right;
while (rightMinNode.left != null) {
rightMinNode = rightMinNode.left;
}
// 右子树删除右子树最小的节点
root.right = deleteNode(root.right, rightMinNode.val);
// 用 leftMaxNode 代替 root
rightMinNode.left = root.left;
rightMinNode.right = root.right;
root = rightMinNode;
}
}
if (key < root.val) {
// 去左子树
root.left = deleteNode(root.left, key);
}
if (key > root.val) {
// 去右子树
root.right = deleteNode(root.right, key);
}
return root;
}