LeetCode Hot100【二叉数-236. 二叉树的最近公共祖先】

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

代码实现
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        // 如果根节点是 p 或 q,或根节点为空,直接返回根节点
        if (root == q || root == p || root == NULL) return root;

        // 递归搜索左子树
        TreeNode* left = lowestCommonAncestor(root->left, p, q);

        // 递归搜索右子树
        TreeNode* right = lowestCommonAncestor(root->right, p, q);

        // 如果左子树和右子树都找到了 p 或 q,说明 root 是公共祖先
        if (left != NULL && right != NULL) return root;

        // 如果左子树为空,右子树非空,返回右子树
        if (left == NULL && right != NULL) return right;

        // 如果右子树为空,左子树非空,返回左子树
        else if (left != NULL && right == NULL) return left;

        // 如果左右子树都为空,返回 NULL
        else return NULL;
    }
};

执行流程

示例输入
root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
树结构
          3
         / \
        5   1
       / \ / \
      6  2 0  8
        / \
       7   4
步骤
  1. 递归搜索左子树:lowestCommonAncestor(5, 5, 1)
    • 找到 p = 5,返回 5
  2. 递归搜索右子树:lowestCommonAncestor(1, 5, 1)
    • 找到 q = 1,返回 1
  3. 左右子树都返回了非空结果,说明公共祖先是 3,即返回 root = 3

最终输出:

3

关键思路

  1. 递归树遍历
    • 从根节点开始,递归向左右子树遍历。
    • 若当前节点是 pq,则返回该节点(可能为 pq,也可能为 NULL)。
  2. 判断当前节点是否是公共祖先
    • 如果 左右子树 都找到 pq,当前节点 root 就是它们的 公共祖先
    • 如果 左子树 返回 NULL,说明 pq 都不在左子树上,返回右子树的结果(反之亦然)。
  3. 递归终止条件
    • 当前节点为空,或者当前节点就是 pq 时返回当前节点。

时间 & 空间复杂度

操作时间复杂度空间复杂度
遍历树的每个节点O(n)O(h)
  • 时间复杂度: 最坏情况下需要遍历树的每个节点,因此时间复杂度是 O(n),其中 n 是树的节点数。
  • 空间复杂度: 空间复杂度主要由递归栈决定,最坏情况下为树的高度 h,即 O(h)。对于平衡树,空间复杂度为 O(log⁡n),对于极端情况的树(如链状树),空间复杂度为 O(n)。

基础语法解析

1. if (root == q || root == p || root == NULL)

  • 递归的终止条件: 如果当前节点是 pq,或者当前节点为空,返回当前节点。
if (root == q || root == p || root == NULL) return root;

2. TreeNode\* left = lowestCommonAncestor(root->left, p, q);

  • 递归向左子树查找公共祖先。
TreeNode* left = lowestCommonAncestor(root->left, p, q);

3. if (left != NULL && right != NULL)

  • 如果左右子树都找到了 pq,则当前节点 root 是最近公共祖先。
if (left != NULL && right != NULL) return root;

4. return left == NULL ? right : left;

  • 如果左子树为空,返回右子树的结果;反之,返回左子树的结果。
if (left == NULL && right != NULL) return right;
else if (left != NULL && right == NULL) return left;

优化 & 变种

变种 1:判断一个节点是否存在于树中

在某些情况下,我们可能需要判断 pq 是否在树中。此时,可以修改 lowestCommonAncestor 函数,添加存在性判断:

bool exists(TreeNode* root, TreeNode* target) {
    if (!root) return false;
    if (root == target) return true;
    return exists(root->left, target) || exists(root->right, target);
}

这个辅助函数用于判断 pq 是否存在于树中。


总结

C++ 语法/结构作用
`if (root == p
left != NULL && right != NULL判断左右子树都找到目标,当前节点为公共祖先
return left == NULL ? right : left;如果左子树为空,返回右子树的结果,反之亦然
时间复杂度: O(n)遍历所有节点
空间复杂度: O(h)递归栈空间
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值