235. 二叉搜索树的最近公共祖先
题目
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]
示例 1:
- 输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
- 输出: 6
- 解释: 节点 2 和节点 8 的最近公共祖先是 6。
思考
这题用通用方法二叉树的公共祖先肯定能做,但是既然是二叉搜索树,那么肯定要根据它的特点来解,这个特点就是如果p、q都大于root就搜右子树,小于就搜左子树,因为二叉搜索树左子树元素都小于root,右子树都大于root,那么当p大于root,q小于root或者p小于q大于时,证明要返回的最近公共祖先就是root,因为如果是次近公共祖先的话,肯定满足之前两个条件,还要继续遍历
代码
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if(root == NULL) return NULL;
//利用二叉搜索树的性质,如果p、q都小于root就向左遍历,如果大于就向右遍历,如果处于root处于中间则root一定是最近公共祖先
if(root->val > p->val && root->val > q->val) {
TreeNode* left = lowestCommonAncestor(root->left, p, q);
if(left != NULL) return left;
}
if(root->val < p->val && root->val < q->val) {
TreeNode* right = lowestCommonAncestor(root->right, p, q);
if(right != NULL) return right;
}
return root;
}
};
701.二叉搜索树中的插入操作
题目
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。
注意,可能存在多种有效的插入方式,只要树在插入后仍保持为二叉搜索树即可。 你可以返回任意有效的结果。
思考
这题初看有点懵,想着根据二叉搜索树的特性,如果val大于root就向右遍历,小于就向左遍历,但是怎么插入呢,看完卡哥视频才发现,其实任何插入的点都能在叶子结点找到其位置,那么当遍历root到nullptr时,返回要插入的点,这样就做到了插入的操作,接着在每一层递归都返回root就行
题目
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
TreeNode* node = new TreeNode(val);
if(root == nullptr) return node;//任意值都能在二叉树的叶子结点的左右子树找到位置
if(root->val < val) root->right = insertIntoBST(root->right, val);
else root->left = insertIntoBST(root->left, val);
return root;
}
};
450.删除二叉搜索树中的节点
题目
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
一般来说,删除节点可分为两个步骤:
首先找到需要删除的节点; 如果找到了,删除它。 说明: 要求算法时间复杂度为 $O(h)$,h 为树的高度。
示例:
思考
本以为可以用插入结点的方式来做,没想到啪啪打脸,因为删除结点需要改变二叉树结构,看完卡哥视频才发现需要考虑五种情况:
1、没找到对应值,直接return nullptr
2、找到对应值并且该结点左右子树都为空(即叶结点),那么直接把该结点变为空,返回nullptr
3、找到对应值并且该结点左子树不为空右子树为空,那么返回root->left,因为要把左子树直接插到root左边
4、找到对应值并且该结点左子树为空右子树不为空,那么返回root->right,因为要把右子树直接插到root右边
5、找到对应值并且该结点左右子树都不为空,这里卡哥给出的方法是先把该结点左子树用一个node替代号,然后找到该结点右子树最接近该结点值的结点,即右子树最左边的值,然后将node插到找到的结点的左边,这里用找到左子树最大值然后将右子树插入应该也可以
代码
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
if(root == nullptr) return nullptr;
if(root->val == key) {
if(root->left == nullptr && root->right == nullptr) return nullptr;
else if(root->left != nullptr && root->right == nullptr) return root->left;
else if (root->left == nullptr && root->right != nullptr) return root->right;
else {
TreeNode* node = root->right;
while(node->left != nullptr) node = node->left;
node->left = root->left;
return root->right;
}
}
if(root->val < key) root->right = deleteNode(root->right, key);
else root->left = deleteNode(root->left, key);
return root;
}
};