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
分析:这个题翻译一下:要求删除一个二叉搜索树上值为key的节点,删除之后的树仍是一个二叉搜索树。
考察的知识点有两个:
1、二叉搜索树如何搜索某个定值
2、二叉搜索出如何删除某个节点
搜索比较简单,根据BST的定义,比较key与当前节点的val就可以递归搜索了。那么如何删除呢?
我的思路是:
首先找到这个节点,如果这个节点是叶子节点,直接置为null并且返回就好了;
如果不是叶子节点:找这个节点的左子树的最大值,或者右子树的最小值,将这个值赋值给当前节点。因为这个极值一定出现在叶子节点上,所以下面就删除这个叶子节点就好了。
代码如下:
1 class Solution { 2 public TreeNode deleteNode(TreeNode root, int key) { 3 if ( root == null ) return null; 4 return helper(root,key); 5 } 6 7 private TreeNode helper(TreeNode node, int key) { 8 if ( node == null ) return null; 9 if ( node.left == null && node.right == null && node.val == key) { 10 node = null; 11 return node; 12 } 13 //递归搜索节点 14 if ( node.val < key ) node.right = helper(node.right,key); 15 if ( node.val > key ) node.left = helper(node.left,key); 16 //替换应该找 右子树最小的值 或者 左子树的最大值。 17 if ( node.val == key ){ 18 if ( node.right != null ){ 19 int val = findminvalinright(node.right); 20 node.val = val; 21 node.right = helper(node.right,val); 22 }else if ( node.left != null ){ 23 int val = findmaxvalinleft(node.left); 24 node.val = val; 25 node.left = helper(node.left,val); 26 } 27 } 28 return node; 29 } 30 31 private int findminvalinright(TreeNode root){ 32 if ( root.left == null ) return root.val; 33 return findminvalinright(root.left); 34 } 35 private int findmaxvalinleft(TreeNode root){ 36 if ( root.right == null ) return root.val; 37 return findmaxvalinleft(root.right); 38 } 39 40 }
运行时间7ms。
这种方法比较繁琐,因为有可能要调用findminvalinright或者findmaxvalinleft两个函数,之所以要调用两个是因为没有判断当前节点的左子树和右子树是否为空。其实如果目标节点左子树为空,直接返回右子树就行了,因为删除这个节点对右子树没有任何影响。需要调整位置仅仅出现在左右子树都不为空的情况。
并且,在寻找左子树的最大值时,我们可以不用另外启一个递归函数,直接用while循环就可以找到左子树的最大值,因为一定是出现在右子树上的。
代码如下:
1 class Solution { 2 public TreeNode deleteNode(TreeNode root, int key) { 3 return helper(root,key); 4 } 5 6 private TreeNode helper(TreeNode node, int key) { 7 if ( node == null ) return null; 8 9 if ( node.val < key ) node.right = helper(node.right,key); 10 else if ( node.val > key ) node.left = helper(node.left,key); 11 else { 12 if ( node.left == null && node.right == null ) return null; 13 else if ( node.left == null ) return node.right; 14 else if ( node.right == null ) return node.left; 15 else { 16 TreeNode t = node.left; 17 while ( t.right != null ) t = t.right; 18 node.val = t.val; 19 node.left = helper(node.left,t.val); 20 } 21 } 22 return node; 23 } 24 25 }