235. 二叉搜索树的最近公共祖先
题目
给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
示例 1:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6
解释: 节点 2 和节点 8 的最近公共祖先是 6。
示例 2:
输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。
解题思路
- 这道题最重要的需要理解的点是:如果root节点的值在 p q 之间,那么该节点一定是 p q 的公共祖先
- 使用二叉搜索树的特性,节点中序遍历是单调递增的。
- 可以通过比较节点 p q 的值和root节点的值来判断是不是公共祖先
- 如果root节点的值大于p q 的值,那么 p q 一定在root的左侧
- 反之,在右侧
- 如果root节点的值在 p q 中间,那么正好就是 p q 的公共祖先
代码
递归法
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root->val > p->val && root->val > q->val) {
// root节点的值比 p q 都大
return lowestCommonAncestor(root->left, p, q);
} else if (root->val < p->val && root->val < q->val) {
// root节点的值比 p q 都小
return lowestCommonAncestor(root->right, p, q);
} else return root;
}
};
迭代法
class Solution {
public:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
while(root) {
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 NULL;
}
};
701.二叉搜索树中的插入操作
题目
给定二叉搜索树(BST)的根节点和要插入树中的值,将值插入二叉搜索树。 返回插入后二叉搜索树的根节点。 输入数据保证,新值和原始二叉搜索树中的任意节点值都不同。
解题思路
- 不需要按照题目的说明改变二叉树的结构,只需要添加在最后面即可
- 这样思路就简单多了,比较大小,然后定位到比较的对象的left 或 right 为空就插入
代码
class Solution {
public:
TreeNode* insertIntoBST(TreeNode* root, int val) {
// 终止条件,如果root为空,说明找到待插入的位置了
// 这里return实际上是return给待插入位置节点的父节点。
// 比如上面例子中,插入0时返回给上一层递归层其实对应的是节点1
if (root == NULL) return new TreeNode(val);
// 左遍历,如果待插入值小,则向左遍历
// 这里赋值的其实就是上面终止条件返回过来的节点
if (val < root->val) root->left = insertIntoBST(root->left, val);
// 同理,向右遍历
if (val > root->val) root->right = insertIntoBST(root->right, val);
// 最终返回root节点,
return root;
}
};
450.删除二叉搜索树中的节点
题目
给定一个二叉搜索树的根节点 root 和一个值 key,删除二叉搜索树中的 key 对应的节点,并保证二叉搜索树的性质不变。返回二叉搜索树(有可能被更新)的根节点的引用。
解题思路
待删除的节点有以下几种情况:
如果目标节点大于当前节点值,则去右子树中删除;
如果目标节点小于当前节点值,则去左子树中删除;
如果目标节点就是当前节点,分为以下三种情况:
- 其无左子:其右子顶替其位置,删除了该节点;
- 其无右子:其左子顶替其位置,删除了该节点;
- 其左右子节点都有:其左子树转移到其右子树的最左节点的左子树上,然后右子树顶替其位置,由此删除了该节点。
代码
class Solution {
public:
TreeNode* deleteNode(TreeNode* root, int key) {
// 情况1
if (root == nullptr) return nullptr;
if (key > root->val) root->right = deleteNode(root->right, key); // 去右子树删除
else if (key < root->val) root->left = deleteNode(root->left, key); // 去左子树删除
else { // root.val == key 找到待删除节点
if (!root->right) return root->left; // 情况2,欲删除节点无右子
if (!root->left) return root->right; // 情况1,欲删除节点无左子
// 情况3,欲删除节点左右子都有
TreeNode *node = root->right; // 找到待删除节点的右子树最左侧的节点
while (node->left) node = node->left; //这里就找到了右子树最左侧节点
node->left = root->left; //将root的左子树,赋值给node节点的左节点
root = root->right; // 用root节点的右子树,替换root节点,即可删除该节点
}
return root;
}
};