示例:
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
思路分析:这题不难,就是需要头脑清晰。
|如果需要删除的节点是当前树的root,
| |如果root->right == NULL,则返回的结果是root->left
| |否则我们需要从root->right寻找到最小的节点tempPtr,并把它从root->right割下来,然后root->left放到tempPtr->left,root->right放到tempPtr->right
|否则我们利用二叉搜索树的性质找需要删除的节点位置以及它的父节点,递归调用自己,删除那个节点,返回拼接好的子树,放回到父节点对应的位置。
比如示例的处理,首先判断root->val == val,不等于,则将root修改为key对应的位置,beforeDel修改为key对应节点的父节点。
然后自己调用自己,当前root(5的左节点3)就是需要删除节点,删除key(5的左节点)前,修改当前root的left和right。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
//寻找到root树中,最小的节点,并且将它从树中截取,并且将root放到这个最小节点的right
TreeNode* findMin(TreeNode *root){
TreeNode *res, *start = root;
//特殊情况,就是root自己
if (root->left == NULL){
return root;
}
//否则一直沿left寻找
while (root->left->left){
root = root->left;
}
//将这个节点从树中割下
res = root->left;
root->left = root->left->right;
//将之前的最初始的root放到这个节点的右端
res->right = start;
return res;
}
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == NULL){
return NULL;
}
//处理特殊情况,删除root
TreeNode *result = root;
if (root->val == key){
if (root->right == NULL){
//root->right为空,结果就是root->left
result = root->left;
}
else{
//修改root->right(将root->right放到root->right中最小的子节点下,放回最小的子节点)
TreeNode *tempPtr = findMin(root->right);
result = tempPtr;
tempPtr->left = root->left;//将root->left放置到tempPtr的left
}
delete root;
return result;
}
//定位到需要删除的节点
TreeNode *beforeDel = root;//需要删除节点的父节点
while (root != NULL && root->val != key){
beforeDel = root;
//二叉搜索树的性质:左子树 < root < 右子树
if (root->val > key){
root = root->left;
}
else{
root = root->right;
}
}
//递归调用自己,删除当前的root
if (beforeDel->left == root){
beforeDel->left = deleteNode(root, key);
}
else{
beforeDel->right = deleteNode(root, key);
}
return result;
}
};