给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。
这道题完全可以利用二叉树的递归原理来解决,
只需要找到要删除的结点,然后判断
- 如果是叶子结点,可以直接删除
- 如果有左子树没有右子树,左子树就代替删除的结点位置
- 如果有右子树,就用右子树上最小的结点来代替删除的结点位置
- 要注意删除结点为跟结点的情况和树中只有一个结点的情况。
今天在刷题的时候又看到了这道题,这次没有用到递归,会显得代码比较复杂,但执行速度好像变快了,就想分享出来。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
//1.首先要删除的结点cur
TreeNode pre = null;
TreeNode cur = root;
while (cur != null) {
if (cur.val == key) {
break;
}
pre = cur;
if (cur.val > key) {
cur = cur.left;
} else {
cur = cur.right;
}
}
if (cur == null) {//说明没有找到,不需要删除任何元素
return root;
}
if (cur.left == null && cur.right == null) {//说明删除的是叶子结点
if (pre == null) {//只有跟结点一个
return null;
}
if (pre.left == cur) {
pre.left = null;
} else {
pre.right = null;
}
return root;
}
if (cur.right == null) {//只有左树
if (pre == null) {//要删除的是跟结点
return root.left;
}
if (pre.left == cur) {
pre.left = cur.left;
} else {
pre.right = cur.left;
}
return root;
}
//2.找到cur的右树上的最小(左)的结点替换cur的位置
if (cur.right == null) {//如果右树等于空
if (pre == null) {
return root.left;
}
pre.left = cur.left;
return root;
}
TreeNode rightCur = getRightMinNode(cur);//得到并删除了右子树中最小的结点
rightCur.left = cur.left;
rightCur.right = cur.right;
if (pre == null) {//如果cur是跟结点
return rightCur;
}
if (pre.left == cur) {
pre.left = rightCur;
} else {
pre.right = rightCur;
}
return root;
}
//找到cur的右树中最小的结点并删除
public TreeNode getRightMinNode(TreeNode cur) {
TreeNode rightCur = cur.right;//右树上最小的结点
TreeNode rightPre = cur;//右树上最小的结点的父结点
if (rightCur.left == null) {
rightPre.right = rightCur.right;
return rightCur;
}
//之后的情况就是rightCur只可能是rightPre的左孩子
while (rightCur.left != null) {
rightPre = rightCur;
rightCur = rightCur.left;
}
rightPre.left = rightCur.right;
return rightCur;
}
}