题目描述
给定一个二叉搜索树的根节点root与一个值key,删除二叉树中的key对应的节点,并保证二叉搜索树的性质不变。返回二叉树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
1. 首先如果找到需要删除的节点;
2. 如果找到了,删除它。
说明:要求算法的时间复杂得复为O(n),h为树的高度。
输入输出样例
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
| 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
|
题解
在之前的几题中,我们主要使用的是二叉搜索树中的几个特性来解题。这道题目我们同样也需要使用它的特性来辅助我们,但是我们还需为其添加一些条件来解题。
首先对于二叉树问题,应先思考对应节点该做什么事情。删除这种事情,不就是拿key值与root的左右节点的值做比较。找到就删除,并相应的调整左右子树的指向。根据这个可以大概的写出一个伪代码来梳理思路
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
|
class Solution { public: TreeNode* deleteNode(TreeNode* root, int key) { return build(root,key); } TreeNode* build(TreeNode* root,int key) { if (root == nullptr) return root;
if (root->right > key) root->left = build(root->left,key); if (root->left < key) root->right = build(root->right,key);
else { TreeNode* rt = root->right; rt->left = root->left; root = root->right; } return root; } };
|
这样做完后,存在几个问题:
1. 如果删除的节点是根节点怎么办?
2. 如果我的左/右节点为空怎么处理?
- 如果删除的节点是根节点,那么使用后序遍历,就应当让root的下一个节点即root右子树的最左顶替。
- 如果为空的话,我先对它进行一个非空判断,如果左为空就直接返回右,右子树同理。
故具体代码如下所示:
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
|
class Solution { public: TreeNode* deleteNode(TreeNode* root, int key) { if (root == nullptr) return root; if (root->val > key) root->left = deleteNode(root->left,key); else if (root->val < key) root->right = deleteNode(root->right,key); else { if (!root->left) return root->right; if (!root->right) return root->left; TreeNode* rt = root->right; while (rt->left) { rt = rt->left; } rt->left = root->left; root = root->right; } return root; } };
|