【Leetcode二叉树的公共祖先问题二】程序员面试金典-面试题04.08.首个共同祖先



面试题04.08

1.问题描述

在这里插入图片描述


2.解决方案

解法一:不包含父亲节点的双递归低效解法

思路很简单,但是需要双递归判断,对于每一个结点都要判断p,q是否被cover!

在这里插入图片描述

//不包含父亲节点的双递归低效解法
class Solution1 {
public:
    //判断p节点是否在以root为根节点的树中
    bool covers(TreeNode* root,TreeNode* p){
        if(root== nullptr) return false;
        if(root!= nullptr&&p== nullptr) return false;

        //先检查是不是根
        if(root==p) return true;

        //再检查在不在子树
        return covers(root->left,p)||covers(root->right,p);

    }
    TreeNode* find(TreeNode* root,TreeNode* p,TreeNode* q){
        if(root== nullptr) return nullptr;

        //
        if(root==p) return p;
        if(root==q) return q;

        //在find函数内p q肯定是都在root里的
        bool a=covers(root->left,p);
        bool b=covers(root->left,q);


        //如果p,q不在root的一边就证明找到了结果就是root
        if(a!=b) return root;

        //p q都在左子树就去左子树找共同祖先的
        if(a&&b) return find(root->left,p,q);

        //p q都在右子树就去右子树找共同祖先的
        if(!a&&!b) return find(root->right,p,q);

        return nullptr;

    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        //首先必须检查合理性
        if(covers(root,p)== false||covers(root,q)== false) return nullptr;

        //在find函数内p q肯定是都在root里的
        return find(root,p,q);
    }
};



解法二:不包含父亲节点的单递归最优化解法(万能解法)

万能解法博客

在这里插入图片描述

//万能解法
class Solution4 {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        //1.必要的检查
        if(root== nullptr) return nullptr;

        //2.可以理解为对于要寻找的节点的判断
        if(root==p||root==q) return root;

        //3.递归调用等待结果
        TreeNode* left=lowestCommonAncestor(root->left,p,q);
        TreeNode* right=lowestCommonAncestor(root->right,p,q);

        //4.根据上面的left,right 空和不空组成的四种结果进行相应的处理
        if(left!= nullptr&&right!= nullptr) return root;
        if(left== nullptr&&right== nullptr) return nullptr;
        if(left== nullptr&&right!= nullptr) return right;
        if(left!= nullptr&&right== nullptr) return left;

        //5.为了通过编译实则不可能从这走
        return nullptr;

    }
};



解法三:深度优先遍历搜索 递归遍历整棵二叉树(力扣官方题解)

在这里插入图片描述
在这里插入图片描述

1.这个算法的精髓在于,是递归但是不是像解法一那样分左右子树那样找,因为分左右子树那样子是自根向下找,那么每一次判断都需要遍历整棵树,时间复杂度肯定高。
2.此算法实则是深度优先搜索先到叶子节点,叶子结点的flson和frson自然得到了,然后深度优先由叶子向上回溯,那么叶子结点的父节点的flson和frson通过子节点的返回值也得到了,说白了就是从叶子节点开始向上传递flson和frson。
3.那么每个节点的flson和frson都知道了,那就可以在自己的递归层中带入我们算法的核心公式
(lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson)),通过这个公式直接判断是否是共同祖先,并且相应的给出返回值回溯到上层计算上层的flson和frson,这个公式上面已经提到。

综上所述,这个算法就是从叶子节点开始遍历整棵树,对整棵树的每一个节点都带入我们的核心公式,然后根据公式的结果判断即可,说白了就是对于每一个节点代入公式是共同祖先就返回,不是就拉倒,去遍历下一个节点,把所有节点都过一遍自然结果就出来了,就这么简单!当然这个公式精确的定义了共同祖先所以才使得算法比较清晰简洁!

//深度优先搜索遍历
class Solution3 {
public:
    TreeNode* ans;
    bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (root == nullptr) return false;
        bool lson = dfs(root->left, p, q);
        bool rson = dfs(root->right, p, q);
        if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
            ans = root;
        }
        return lson || rson || (root->val == p->val || root->val == q->val);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        dfs(root, p, q);
        return ans;
    }
};
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值