[力扣c++实现]236. 二叉树的最近公共祖先

236. 二叉树的最近公共祖先

1. 题目描述

指定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:

输入:root = [1,2], p = 1, q = 2
输出:1

提示:

树中节点数目在范围 [2, 105] 内。
-109 <= Node.val <= 109
所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。

2. 情况分析

题目要求的公共祖先, p,q两节点在树中的关系为如下三种:

(1)  q位于p祖先的左分支.(互换pq也成立)
       {p/q}
        /
       /
      /
    {q/p}

(2) q位于p祖先的右分支.(互换pq也成立)
     {p/q}
        \
         \
          \
         {q/p}

(3) p,q分布在祖先的不同分支上
    {parent}
      /   \
     /     \
    /       \
 {p/q}     {q/p}

所以, p, q只有如上三种关系,

对于(1) + (2), 我们判断某个节点是否在另外一个节点的上一层次,如果是,那么上层节点肯定就是下层节点的祖先.

if (p->left == q or p->right == q or p == root )
    return p;

if (q->left == p or q->right == p or q == root )
    return p;

对于(3),公共祖先就是root,无论p,q分别分布于左右分支的节点的路径分别有多长.但是,如何寻找到这种关系呢?
当我们无法确定两个节点p,q 位于当前root节点的的同一个分支还是不同分支, 因此我们需要进行递归判断, 不仅要判断左边分支, 还要判断右边分支.

TreeNode* left = lowestCommonAncestor(root->left, p, q);
TreeNode* right = lowestCommonAncestor(root->right, p, q);

if (left && right) {
    return root;
}

return left?left:right;

即,我们从root节点进入,发现我们的两个节点分别分布于两个分支下,那么我们就可以得知,root节点一定为最近公共祖先节点.

3.代码如下

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if (not root)
            return nullptr;
        if (p->left == q || p->right == q || p == root) {
            return p;
        }

        if (q->left == p || q->right == p || q == root) {
            return q;
        }

        TreeNode* left = lowestCommonAncestor(root->left, p, q);
        TreeNode* right = lowestCommonAncestor(root->right, p, q);

        if (left && right) {
            return root;
        }

        return left?left:right;
    }
};
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值