目录
- 235、二叉搜索树的最近公共祖先
- 701、二叉搜索树中的插入操作
- 450、删除
235、二叉搜索树的最近公共祖先
回忆一下递归的三部曲,以这题为例。
1、参数:
- 当前节点和两个节点。
Treenode* cur, Treenode*p, Treenode*q
2、递归终止条件:
遇到空返回就可以
if (cur==NULL) return cur;
3、确定单层递归逻辑
- 遍历二叉搜索树的时候就是寻找区间[p->val, q->val](注意这里是左闭又闭)那么如果 cur->val 大于 p->val,同时 cur->val 大于q->val,那么就应该向左遍历(说明目标区间在左子树上)。需要注意的是此时不知道p和q谁大,所以两个都要判断。
if (cur->val > p->val && cur->val > q->val) {TreeNode* left = traversal(cur->left, p, q);if (left != NULL) {return left;}
}
同理右边搜索也是一样。
所以本题的整体代码如下:
class Solution {
private:TreeNode* traversal(TreeNode* cur, TreeNode* p, TreeNode* q){if(cur->val > p->val & cur->val > q->val){TreeNode* left = traversal(cur->left, p, q);if (left!=NULL){return left;}}if(cur->val < p->val & cur->val < q->val){TreeNode* right = traversal(cur->right, p, q);if (right!=NULL){return right;}}return cur;}public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {return traversal(root, p, q);}
};
701、二叉搜索树中的插入操作
讲解:https://programmercarl.com/0701.%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%9A%84%E6%8F%92%E5%85%A5%E6%93%8D%E4%BD%9C.html
不停向尾部插入节点,当遍历到空节点时就是叶子节点,这时候申请一个新节点存放插入值。
class Solution {
public:TreeNode* insertIntoBST(TreeNode* root, int val) {if (root == NULL) {TreeNode* node = new TreeNode(val);return node;}if (root->val > val) root->left = insertIntoBST(root->left, val);if (root->val < val) root->right = insertIntoBST(root->right, val);return root;}
};
450、删除
二叉搜索树中的节点
讲解:https://programmercarl.com/0450.%E5%88%A0%E9%99%A4%E4%BA%8C%E5%8F%89%E6%90%9C%E7%B4%A2%E6%A0%91%E4%B8%AD%E7%9A%84%E8%8A%82%E7%82%B9.html
递归三部曲。
理解一下此题的动画过程,第五种情况。
class Solution {
public:TreeNode* deleteNode(TreeNode* root, int key) {if (root == nullptr) return root; // 第一种情况:没找到删除的节点,遍历到空节点直接返回了if (root->val == key) {// 第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点if (root->left == nullptr && root->right == nullptr) {///! 内存释放delete root;return nullptr;}// 第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点else if (root->left == nullptr) {auto retNode = root->right;///! 内存释放delete root;return retNode;}// 第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点else if (root->right == nullptr) {auto retNode = root->left;///! 内存释放delete root;return retNode;}// 第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置// 并返回删除节点右孩子为新的根节点。else {TreeNode* cur = root->right; // 找右子树最左面的节点while(cur->left != nullptr) {cur = cur->left;}cur->left = root->left; // 把要删除的节点(root)左子树放在cur的左孩子的位置TreeNode* tmp = root; // 把root节点保存一下,下面来删除root = root->right; // 返回旧root的右孩子作为新rootdelete tmp; // 释放节点内存(这里不写也可以,但C++最好手动释放一下吧)return root;}}if (root->val > key) root->left = deleteNode(root->left, key);if (root->val < key) root->right = deleteNode(root->right, key);return root;}
};