找工作准备刷题Day8 二叉树 (卡尔41期训练营 7.22)

第一题: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;
    }
};

要点

  1.  p和q都大于root->val,可以判定,其在root的右子树上;
  2.  p和q都小于root->val,可以判定,其在root的左子树上;
  3. 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. 二叉搜索树中的插入操作

题目描述

 要点

  1. Node.val值独一无二且在原始BST中不存在(其实这种限制脱离实际,在解题时应该基于更加复杂的环境多思考)
  2. 对于root和val值,如果root->val大于val,取root->left;如果root->val小于val,取root->right
  3. 需要时刻牢记返回值的意义。

题解

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;
    }
};

要点

  1. 当 root 为空时,找不到key,返回 nullptr;
  2. 当 root 取值大于key时,在左子树进行删除,并返回删除后的左子树;
  3. 当 root 取值小于key时,在右子树进行删除,并返回删除后的右子树;
  4. 当 root 取值为key时,存在以下几种情况:

【1】、左子树和右子树均为nullptr,delete root,返回nullptr即可;

【2】、左子树或者右子树其中一个为nullptr时,delete root,返回不为空的子树;

【3】、左右子树均不为空,为了保证删除root后仍为二叉搜索树,可以将左子树设置为右子树最左边节点的左子树(详见代码,下图从卡尔代码网复制过来的)。

题解2——不利用二叉搜索树,通用方法(交换)

解题思路

  1. 找到待删除的节点
  2. 将待删除的节点与其右子树最左侧节点交换,此时待删除节点换到了底层(不一定是叶子节点)
  3. 很绕很绕。。。

代码

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;
    }
};

  • 25
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值