代码训练营Day.22 | 235. 二叉搜索树的最近公共祖先、701. 二叉搜索树中的插入操作、450. 删除二叉搜索树中的节点

235. 二叉搜索树的最近公共祖先

1. LeetCode链接

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

2. 题目描述

3. 解法

利用二叉搜索树的特性进行公共节点的判断:

1. 此节点为公共节点:p、q恰好在此节点的左右棵子树上。即,root的val在p、q的val所构成的闭区间内。

2. 如果p、q的val恰好都大于root的val,则只需要考虑root->right

3. 如果p、q都小于root,则只考虑root->left

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == NULL) return NULL;
        if (root->val <= p->val && root->val >= q->val || root->val >= p->val && root->val <= q->val) return root;
        else if (p->val > root->val && q->val > root->val) return lowestCommonAncestor(root->right, p, q);
        else return lowestCommonAncestor(root->left, p, q);
    }
};

更精简一点

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (p->val > root->val && q->val > root->val) return lowestCommonAncestor(root->right, p, q);
        else if (p->val < root->val && q->val < root->val) return lowestCommonAncestor(root->left, p, q);
        else return root;
    }
};

迭代法

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        queue<TreeNode*> qu;
        qu.push(root);
        TreeNode* cur;
        while (!qu.empty()) {
            cur = qu.front();
            qu.pop();
            if (q->val < cur->val && p->val < cur->val) qu.push(cur->left);
            else if (q->val > cur->val && p->val > cur->val) qu.push(cur->right);
            else break;
        }
        return cur;
    }
};

更加精简的:

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. 二叉搜索树中的插入操作

1. LeetCode链接

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

2. 题目描述

 

3. 解法

先在二叉搜索树中查询val,直到找到NULL,然后将val插入该NULL。

迭代:

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        TreeNode* a = new TreeNode(val);
        if (root == NULL) return a;
        TreeNode* cur = root;
        while (cur) {
            if (cur->val > val && cur->left != NULL) cur = cur->left;
            else if (cur->val > val && cur->left == NULL) {
                cur->left = a;
                break;
            }
            else if (cur->val < val && cur->right != NULL) cur = cur->right;
            else {
                cur->right = a;
                break;
            }
        }
        return root;
    }
};

递归。相当于将在遍历至NULL的路上,重新连接原本的树,直到遇到NULL,然后把NULL换成val。

1. 参数和返回值。参数:当前节点和val。返回值:当前节点。

2. 终止条件。遇到NULL且将NULL替换为val。

3. 比较root和val确定从左子树走还是右子树走,root->left = root->left  /  root->right = root->right;

class Solution {
public:
    TreeNode* insertIntoBST(TreeNode* root, int val) {
        if (root == NULL) {
            TreeNode* n = new TreeNode(val);
            return n;
        }
        if (root->val > val) root->left = insertIntoBST(root->left, val);
        if (root->val < val) root->right = insertIntoBST(root->right, val);
        return root;
    }
};

450. 删除二叉搜索树中的节点

1. LeetCode链接

力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

2. 题目描述

3. 解法

删除节点后,需要考虑是让左子树上位还是右子树上位。这道题的话,无所谓,暂且让左子树上位吧。这个时候问题来了,右子树该如何安排?

其实这道题目可以看成左子树上位后,将右子树插入左子树,因为两边都是二叉搜索树,且左子树必小于右子树,所以只要简单插入即可。

class Solution {
public:
    TreeNode* insertNode(TreeNode* root, TreeNode* key) {
        if (root == NULL) return key;
        if (key == NULL) return root;
        if (key->val > root->val) root->right = insertNode(root->right, key);
        if (key->val < root->val) root->left = insertNode(root->left, key);
        return root;
    }
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == NULL) return NULL;
        if (root->val == key) {
            TreeNode* left = root->left;
            TreeNode* right = root->right;
            delete root;
            return insertNode(left, right);
        }
        if (key > root->val) root->right = deleteNode(root->right, key);
        if (key < root->val) root->left = deleteNode(root->left, key);
        return root;
    }
};

细想的话,其实如果将左子树上位,右子树一定被插在左子树中的最右节点的右节点上;如果让右子树上位,左子树一定被插在最左节点的左节点上。

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == NULL) return NULL;
        if (root->val == key) {
            TreeNode* left = root->left;
            TreeNode* right = root->right;
            delete root;
            if (left == NULL) return right;
            if (right == NULL) return left;
            TreeNode* cur = left;
            while (left != NULL && left->right != NULL) left = left->right;
            left->right = right;
            return cur;
        }
        if (key > root->val) root->right = deleteNode(root->right, key);
        if (key < root->val) root->left = deleteNode(root->left, key);
        return root;
    }
};

更巧妙的是,删除当前节点后,最合适的候选节点是左子树最右节点或者右子树最左节点。可以通过交换val值,将root换到底部,然后再遇到root后直接删除。

class Solution {
public:
    TreeNode* deleteNode(TreeNode* root, int key) {
        if (root == nullptr) return root;
        if (root->val == key) {
            if (root->right == nullptr) { // 这里第二次操作目标值:最终删除的作用
                return root->left;
            }
            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;
    }
};

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值