450. 删除二叉搜索树中的节点(一般)

给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。

一般来说,删除节点可分为两个步骤:

首先找到需要删除的节点;
如果找到了,删除它。
说明: 要求算法时间复杂度为 O(h),h 为树的高度。

示例:

root = [5,3,6,2,4,null,7]
key = 3

        5
       / \
       3   6
     / \   \
    2   4   7
    给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。

一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。

    5
   / \
  4   6
 /     \
2       7

另一个正确答案是 [5,2,6,null,4,null,7]。

    5
   / \
  2   6
   \   \
    4   7

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/delete-node-in-a-bst

思路:

删除需要分好几种情况:

  • 如果左子和右子都没有:直接删,因为是叶子节点,不会影响
  • 如果左有右无,或者左无右有,直接删,因为也不会影响搜索树结构
  • 如果都有:那么一定会破坏结构,需要根据一定规则删除
    • 将待删节点的左子树放到后续节点的最左边的左子树上
    • 将待删节点的右子树,作为后续节点补入
    • 也可以是左子树为后续节点,右子树放到后续节点的最右子树上

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Solution {
public TreeNode deleteNode(TreeNode root, int key) {
//删除需要考虑的点有很多
if(root==null){
return root;
}
//分情况,什么序无所谓(考虑中序)
//1.删除左叶子或者右叶子
//2.删除叶子节点的父节点
//2.1左子不在
//2.2右子不在
//2.3两个都在
if(root.val==key){
//如何删除
if(root.left==null && root.right==null){
return null;//不能是root,要不然有个用例过不了
}else if(root.left!=null && root.right==null){
return root.left;
}else if(root.right!=null && root.left==null){
return root.right;
}else {
//都不为空咋办
//待删除节点的右子树作为后继节点,将待删除节点的左子树赋给后继节点的最底层左子树上(或者左右反过来,这个是规则)
//1.首先需要有个指针指向右子树的最左节点
TreeNode rightnode = root.right;
while (rightnode.left!=null){
rightnode = rightnode.left;
}
rightnode.left = root.left;
//现在替换root
root.left = null;
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;
}
}