给定一个二叉搜索树的根节点 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 74 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 代替 rootleftMaxNode.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 代替 rootrightMinNode.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 代替 rootleftMaxNode.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 代替 rootrightMinNode.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;}
