题目描述
解题思路
递归法
- 确定递归函数参数以及返回值
说道递归函数的返回值,在搜索树中的插入操作(opens new window)中通过递归返回值来加入新节点, 这里也可以通过递归返回值删除节点。
- 确定终止条件
遇到空返回,其实这也说明没找到删除的节点,遍历到空节点直接返回了
- 单层处理逻辑
- 第一种情况:没找到删除的节点,遍历到空节点直接返回了
- 找到删除的节点
- 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
- 第三种情况:删除节点的左孩子为空,右孩子不为空,删除节点,右孩子补位,返回右孩子为根节点
- 第四种情况:删除节点的右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
- 第五种情况:左右孩子节点都不为空,则将删除节点的左子树头结点(左孩子)放到删除节点的右子树的最左面节点的左孩子上,返回删除节点右孩子为新的根节点。
第五种情况:
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return null;
}
if (root.val == key) {
// 情况一:左为空,右不为空
if (root.left == null && root.right != null) return root.left;
// 情况二:左不为空,右为空
else if (root.left != null && root.right == null) return root.right;
// 情况三:左右都为空,直接删除
else if (root.left == null && root.right == null) return null;
// 情况四:左右都不为空,那么左节点放到右节点的最左边的节点
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;
}
迭代法
// 迭代法
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) {
return null;
}
TreeNode pre = null;
TreeNode cur = root;
while (cur != null) {
if (cur.val == key) break;
// 一定放在break后面,因为pre是cur的父节点
pre = cur;
if (cur.val > key) cur = cur.left;
else if (cur.val < key) cur = cur.right;
}
if (pre == null) {
return deleteNodes(cur);
}
// 得知道是删除那个节点(也就是知道cur是pre的左节点还是右节点)
if (pre.left != null && pre.left.val == key) {
pre.left = deleteNodes(cur);
}
if (pre.right != null && pre.right.val == key) {
pre.right = deleteNodes(cur);
}
return root;
}
// 删除节点的4种情况(迭代的删除节点)
public TreeNode deleteNodes(TreeNode target) {
if (target == null) return target;
if (target.left == null) return target.right;
if (target.right == null) return target.left;
TreeNode cur = target.right;
while (cur.left != null) {
cur = cur.left;
}
cur.left = target.left;
return target.right;
}