今日主要总结一下,450. 删除二叉搜索树中的节点,并且一文搞懂怎么删除二叉搜索树和普通二叉树对应节点
题目:450. 删除二叉搜索树中的节点
题目描述:
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点;
如果找到了,删除它。
示例 1:
输入:root = [5,3,6,2,4,null,7], key = 3
输出:[5,4,6,2,null,null,7]
解释:给定需要删除的节点值是 3,所以我们首先找到 3 这个节点,然后删除它。
一个正确的答案是 [5,4,6,2,null,null,7], 如下图所示。
另一个正确答案是 [5,2,6,null,4,null,7]。
示例 2:
输入: root = [5,3,6,2,4,null,7], key = 0
输出: [5,3,6,2,4,null,7]
解释: 二叉树不包含值为 0 的节点
示例 3:
输入: root = [], key = 0
输出: []
提示:
节点数的范围 [0, 104].
-105 <= Node.val <= 105
节点值唯一
root 是合法的二叉搜索树
-105 <= key <= 105
本题重难点
删除二叉搜索树某个节点并保证二叉搜索树的性质不变就要使用高中时数学常用的分类讨论思想:
该题一共分为五种情况
1、没有找到对应要删除的key值的节点
2、要删的节点左右节点都为空,为叶子节点
3、要删的节点左节点为空,右节点不为空
4、要删的节点右节点为空,左节点不为空
5、要删的节点的左、右节点都不为空(也是最复杂的一种情况)
一、不带释放内存版本
C++代码
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(!root) return nullptr;//情况1
if(root->val == key){
if(!root->left && !root->right) return nullptr;//情况2
else if(!root->left) return root->right;//情况3
else if(!root->right) return root->left;//情况4
else{//情况5
TreeNode* cur = root->right;
while(cur->left){
cur = cur->left;
}
cur->left = root->left;
return root->right;
}
}
if(root->val > key) root->left = deleteNode(root->left, key);
if(root->val < key) root->right = deleteNode(root->right, key);
return root;
}
};
对于C++来说,上述写法并没有真正释放掉内存,最好手动释放一下
二、带释放内存版本
C++代码
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(!root) return nullptr;//情况1
if(root->val == key){
if(!root->left && !root->right)//情况2
{
delete root;
return nullptr;
}
else if(!root->left)//情况3
{
TreeNode* retNode = root->right;
delete root;
return retNode;
}
else if(!root->right)//情况4
{
TreeNode* retNode = root->left;
delete root;
return retNode;
}
else{//情况5
TreeNode* cur = root->right;
while(cur->left){
cur = cur->left;
}
cur->left = root->left;
TreeNode* retNode = root->right;
delete root;
return retNode;
}
}
if(root->val > key) root->left = deleteNode(root->left, key);
if(root->val < key) root->right = deleteNode(root->right, key);
return root;
}
};
三、通用删除普通二叉树节点方法
作为拓展,再介绍一种通用的删除,普通二叉树的删除方式(没有使用搜索树的特性则需要遍历整棵树),可以用交换值的操作来删除目标节点。
代码中目标节点(要删除的节点)被操作了两次:
- 第一次是和目标节点的右子树最左面节点交换。
- 第二次直接被NULL覆盖了。
如果光看文字不太理解可以看下图理解一下:
C++代码
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(!root) return nullptr;//情况1
if(root->val == key){
if(!root->left && !root->right)//情况2
{
delete root;
return nullptr;
}
else if(!root->left)//情况3
{
TreeNode* retNode = root->right;
delete root;
return retNode;
}
else if(!root->right)//情况4
{
TreeNode* retNode = root->left;
delete root;
return retNode;
}
else{//情况5
TreeNode* cur = root->right;
while(cur->left){
cur = cur->left;
}
swap(root->val, cur->val);
}
}
root->left = deleteNode(root->left, key);
root->right = deleteNode(root->right, key);
return root;
}
};
总结
本文详解了怎么删除二叉搜索树和普通二叉树节点的方法,本质上都是分了5种情况,二叉搜索树第五种情况是把要删除节点的左子树接到删除节点的右子树最左面一个节点的下面。
而普通二叉树是采用可以用交换要删除节点值和要删除节点的右子树最左面一个节点的值操作来删除目标节点。
欢迎大家关注本人公众号:编程复盘与思考随笔
(关注后可以免费获得本人在csdn发布的资源源码)
公众号主要记录编程和刷题时的总结复盘笔记和心得!并且分享读书、工作、生活中的一些思考感悟!