LeetCode Project
450.Delete Node in a BST
- Difficulty : Medium
Description :
Given a root node reference of a BST and a key, delete the node with the given key in the BST. Return the root node reference (possibly updated) of the BST.
Basically, the deletion can be divided into two stages:
- Search for a node to remove.
- If the node is found, delete the node.
Note: Time complexity should be O(height of tree).
Example:
root = [5,3,6,2,4,null,7] key = 3 5 / \ 3 6 / \ \ 2 4 7 Given key to delete is 3. So we find the node with value 3 and delete it. One valid answer is [5,4,6,2,null,null,7], shown in the following BST. 5 / \ 4 6 / \ 2 7 Another valid answer is [5,2,6,null,4,null,7]. 5 / \ 2 6 \ \ 4 7
题意为给出一棵搜索二叉树,并给出一个要删除的数字,在二叉树中寻找到该数字的节点,并将它删除,删除后要确保该二叉树仍未一棵搜索二叉树。
搜索二叉树是一种特殊的二叉树,在建立该树时将遵循这样一个规则:每个节点的左子树的值必定小于它的值,它的右子树的值必定大于它的值。
因此,当给定一定的数的时候,若建树时的顺序不一样,最后得到的树也将不一样,但是无论如何,它都符合搜索二叉树的定义。
此树在进行搜索时,近似于进行折半查找,故其平均时间复杂度为O(logn),但存在极端的情况,若给定的序列是有序的,此时该树将一直倾向于一边,此时退化为顺序查找,时间复杂度为O(n)。对于这种情况,我们可以将该二叉搜索树平衡化处理——即建造AVL树,此处不过多展开。
下图给出两种方法处理该题:
1.利用循环解决:
public static TreeNode deleteNode(TreeNode root,int key){
boolean solve = false;
TreeNode temp = root;
TreeNode parent = null;
while (temp != null && !solve){
if (temp.val == key){
solve = true;
}else if (key > temp.val){
parent = temp;
temp = temp.right;
}else if (key < temp.val){
parent = temp;
temp = temp.left;
}
}
if (!solve)
return root;
if (temp.left == null && temp.right == null){
if (temp == root)
return null;
else if (parent.left == temp)
parent.left = null;
else
parent.right = null;
}else if (temp.left == null || temp.right == null){
if (temp == root)
if (temp.left == null)
return temp.right;
else
return temp.left;
else
if (parent.left == temp && temp.left != null){
parent.left = temp.left;
}else if (parent.left == temp){
parent.left = temp.right;
}else if (parent.right == temp && temp.left != null){
parent.right = temp.left;
}else {
parent.right = temp.right;
}
}else{
TreeNode t = temp;
TreeNode tc = temp.right;
while (tc.left != null){
t = tc;
tc = tc.left;
}
temp.val = tc.val;
if (t == temp)
t.right = tc.right;
else
t.left = tc.right;
}
return root;
}
具体思想就是先找出要删除的点与其父节点,然后将该节点的右子树的最左节点(最小)复制到被删除节点,然后直接删除最左节点,若该节点存在右子树,则将其右子树链接至其父节点的左子树上。
给出一个测试用例的图:
解得:
关注1图中33节点与34节点。
解法二:
利用递归删除,这种写法的好处是十分简短,时间复杂度较类似,但是本人比较难将这种方法想出来(递归学得不好)。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public TreeNode deleteNode(TreeNode root,int key){
if (root == null){
return root;
}
if (root.val < key){
root.right = deleteNode(root.right,key);
}else if (root.val >key){
root.left = deleteNode(root.left,key);
}else if (root.left != null && root.right != null){
root.val = findMin(root.right).val;
root.right = deleteNode(root.right,root.val);
}else{
root = (root.left != null) ? root.left : root.right;
}
return root;
}
public TreeNode findMin(TreeNode root){
while (root.left != null){
root = root.left;
}
return root;
}
}
解:
注意到35节点处发生了形状的改变,这是由于进行了递归删除,清除了33节点后,再清除34节点,故形成了该形状。