第一题:Leetcode235. 二叉搜索树的最近公共祖先
题目描述
题解1——递归法
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr)
return nullptr;
if (root->val > p->val && root->val > q->val) {
TreeNode* left = lowestCommonAncestor(root->left, p, q);
if (left != nullptr)
return left;
}
if (root->val < p->val && root->val < q->val) {
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if (right != nullptr)
return right;
}
// p和q一个在左子树,一个在右子树,返回root
return root;
}
};
要点
- p和q都大于root->val,可以判定,其在root的右子树上;
- p和q都小于root->val,可以判定,其在root的左子树上;
- p和q一个在左子树,一个在右子树,返回root。
题解2——迭代法
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while (root != nullptr) {
if (root->val > p->val && root->val > q->val)
root = root->left;
else if (root->val < p->val && root->val < q->val)
root = root->right;
else
return root;
}
return nullptr;
}
};
原理同递归法。
第二题:Leetcode701. 二叉搜索树中的插入操作
题目描述
要点
- Node.val值独一无二且在原始BST中不存在(其实这种限制脱离实际,在解题时应该基于更加复杂的环境多思考)
- 对于root和val值,如果root->val大于val,取root->left;如果root->val小于val,取root->right
- 需要时刻牢记返回值的意义。
题解
class Solution {
public:
// 返回插入后树的根节点
TreeNode* insertIntoBST(TreeNode* root, int val) {
if (root == nullptr) {
// 到达插入位置
root = new TreeNode(val);
return root;
}
if (root->val > val)
root->left = insertIntoBST(root->left, val);
else
root->right = insertIntoBST(root->right, val);
return root;
}
};
第三题:Leetcode450. 删除二叉搜索树中的节点
题目描述
解题思路
根据二叉搜索树的特性:根节点大于所有左子树节点,根节点小于所有右子树节点。
据此可以写出题解1。
对于普通二叉树,可以写出题解2。
题解1——利用二叉搜索树的特性
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr)
return nullptr;
if (root->val == key) {
// root为叶子节点,delete root并返回nullptr
if (root->left == nullptr && root->right == nullptr) {
delete root;
return nullptr;
}
// 左子树或者右子树其中一个为nullptr,另一个存在,返回存在的,并删除root
if (root->left == nullptr || root->right == nullptr) {
TreeNode* returnNode =
root->left == nullptr ? root->right : root->left;
delete root;
return returnNode;
}
// 左右子树都存在,将左子树 设置为 右子树最左边节点的左儿子
if (root->left != nullptr && root->right != nullptr)
{
TreeNode* node = root->right;
while(node->left)
node = node->left;
node->left = root->left;
TreeNode* toDelete = root;
root = root->right;
delete toDelete;
return root;
}
} else if (root->val > key)
root->left = deleteNode(root->left, key);
else
root->right = deleteNode(root->right, key);
return root;
}
};
要点
- 当 root 为空时,找不到key,返回 nullptr;
- 当 root 取值大于key时,在左子树进行删除,并返回删除后的左子树;
- 当 root 取值小于key时,在右子树进行删除,并返回删除后的右子树;
- 当 root 取值为key时,存在以下几种情况:
【1】、左子树和右子树均为nullptr,delete root,返回nullptr即可;
【2】、左子树或者右子树其中一个为nullptr时,delete root,返回不为空的子树;
【3】、左右子树均不为空,为了保证删除root后仍为二叉搜索树,可以将左子树设置为右子树最左边节点的左子树(详见代码,下图从卡尔代码网复制过来的)。
题解2——不利用二叉搜索树,通用方法(交换)
解题思路
- 找到待删除的节点
- 将待删除的节点与其右子树最左侧节点交换,此时待删除节点换到了底层(不一定是叶子节点)
- 很绕很绕。。。
代码
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr)
return root;
if (root->val == key) {
// 第二次操作,将已经被调换到最下方的待删除节点删除
// 此处,当root的右子树为空,直接返回左子树即可。
// 因此,其完成两部分内容:第二次删除 + 处理右子树为空情况。
if(root->right == nullptr)
{
return root->left;
}
// 进入这里,则右子树不为空,左子树有可能为nullptr
TreeNode* cur = root->right;
while (cur->left)
cur = cur->left;
swap(cur->val, root->val);//第一次操作,把待删除的值换到右子树最左边节点
}
root->left = deleteNode(root->left, key);
root->right = deleteNode(root->right, key);
return root;
}
};