LeetCode 剑指 Offer 68 - II. 二叉树的最近公共祖先

这篇博客探讨了如何在一般二叉树中寻找两个目标节点的最近公共祖先。作者首先介绍了二叉搜索树中简单的方法,然后转向解决一般二叉树的问题。通过递归的方式,检查目标节点是否在当前根节点的左右子树中,并根据返回值进行判断。文章提到了一种高效的解决方案,并展示了C语言实现的代码,同时分享了自己最初的超时解决方案,以展示不同的思考过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接
之前做了二叉搜索树的最近公共祖先寻找,因为搜索树的有序性,很好做。但是这个题换成了一般二叉树,递归上略微复杂。

看了评论里面大神的杰作,实在太nb了嗷。本质上和我的想法是一样的,都是在看目标节点是否在根节点的左右子树中,注意返回值的写法,判断结构 A ? B : C 其中的 B 和C是可以嵌套使用该结构的,学到了。

给出代码:

struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
    /* 二叉树为空或者结点 p/q 为根结点 */
    if (root == NULL || root == p || root == q) {
        return root;
    }

    /* 在根结点的左右子树查找 */
    struct TreeNode *left = lowestCommonAncestor(root->left, p, q);
    struct TreeNode *right = lowestCommonAncestor(root->right, p, q);
    
    /* 结点 p/q 不在左子树中,就在右子树中查找,如果能找到,就返回在右子树中找到的结点(反之亦然) */
    /* 结点 p/q 分别存在左右两颗子树, 根结点为最近公共祖先 */
    /* 结点 p/q 在左右子树都找不到,则它们没有最近公共祖先 */
    return left == NULL ? right : right == NULL ? left : root;     
}

以下是我的第一次想的思路:

  1. 每个节点判断一次,是否有目标节点在以这个节点为根节点的子树中,isThere()函数返回在与否的真值。
  2. 从根节点开始看。如果在,则看其左右子树的isThere()函数返回值。
  3. 如果公共子节点不是目标节点之间的一个,至少有一个子树的isThere()函数值为true,进入返回值为true的子树中,递归进入isThere()返回值为true的树,直到左右子树的isThere()返回值都是true。证明找到了这个节点,赋值给全局变量result。
  4. 如果公共子节点是目标节点之间的一个呢,再返回节点之前稍微判断一下,如果是就把当前根节点赋值给result。
  5. 返回result。

值得注意的是,这里result更新的时候,是函数按照出栈的顺序更新的,所以要把第4点说到的情况放在return前面。

但是毫不意外的超时了哈哈哈,因为递归的次数太多了,双重递归有点沙雕,但是感觉值得记录一下这种思路。

给出代码(这次换成了C语言):

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

struct TreeNode* result;

// 判断目标子节点是否在该以 root 为根的子树中,如果在,就返回true,不在返回false
bool isThere(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
    if(!root) return false;
    if(root->val == p->val || root->val == q->val) return true;
    return isThere(root->left,p,q) || isThere(root->right,p,q);
}

struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q){
    if(isThere(root, p, q)){   // 只有此节点中包含有目标节点才能进一步判断
        if(isThere(root->left,p,q)  && isThere(root->right, p, q)) result = root;   // 如果左右子节点中均存在目标节点,证明这个是他们的公共祖先节点
        else if(isThere(root->left, p, q)) lowestCommonAncestor(root->left, p, q);    // 进入左右子节点中isThere函数返回值是true的分支判断
        else if(isThere(root->right, p, q)) lowestCommonAncestor(root->right, p, q);
    }
    if(root->val == p->val || root->val == q->val) result = root;  // 看根节点是否是目标节点两个之间的一个
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值