二叉树中两个指定节点的最近公共祖先

二叉树中两个指定节点的最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

在二叉树中,两个节点的最近公共祖先(LCA)是指同时是这两个节点的祖先的最低节点(即深度最大的共同祖先)。例如,给定一个二叉树,节点A和节点B的LCA是树中第一个同时包含A和B在其子树中的节点。这个问题可以通过递归遍历树来解决,核心思想是利用后序遍历来检查节点之间的关系。

解题思路
  • 递归方法:从根节点开始,递归地遍历左子树和右子树。如果当前节点是其中一个目标节点(p或q),则返回该节点;如果在左子树和右子树中都找到了目标节点,则当前节点就是LCA;否则,返回非null的子节点结果。
  • 关键点:算法基于后序遍历(左-右-根),因为它需要先处理子树,再处理根节点,从而自底向上地确定LCA。
  • 边界条件:如果树为空或目标节点不存在,返回null;如果目标节点是根节点,则根节点就是LCA。
算法流程
  1. 基本检查
    • 如果当前节点为null,返回null。
    • 如果当前节点是p或q中的一个,返回当前节点(表示找到了一个目标节点)。
  2. 递归遍历
    • 递归地在左子树中查找p和q。
    • 递归地在右子树中查找p和q。
  3. 结果合并
    • 如果左子树和右子树的递归结果都非null,表示当前节点是LCA(因为p和q分布在左右子树中)。
    • 如果只有左子树结果非null,返回左子树结果(表示LCA在左子树中)。
    • 如果只有右子树结果非null,返回右子树结果(表示LCA在右子树中)。
    • 如果都null,返回null(表示未找到)。

该算法的时间复杂度为O(n),其中n是树中的节点数,因为每个节点被访问一次。空间复杂度为O(h),其中h是树的高度,主要用于递归栈。

Java实现

以下是Java代码实现。假设树节点定义为TreeNode类,包含值、左子节点和右子节点。

java 复制代码
class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        // 边界条件:如果根节点为空,或根节点就是p或q,直接返回根节点
        if (root == null || root == p || root == q) {
            return root;
        }
        
        // 递归遍历左子树和右子树
        TreeNode left = lowestCommonAncestor(root.left, p, q);
        TreeNode right = lowestCommonAncestor(root.right, p, q);
        
        // 如果左右子树都非null,当前节点是LCA
        if (left != null && right != null) {
            return root;
        }
        // 否则,返回非null的子节点结果
        return left != null ? left : right;
    }
}
C语言实现

在C语言中,我们定义树节点结构体,并实现递归函数。注意内存管理。

c 复制代码
#include <stdlib.h>

struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
};

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);
    
    // 如果左右子树都非null,当前节点是LCA
    if (left != NULL && right != NULL) {
        return root;
    }
    // 否则,返回非null的子节点结果
    return left != NULL ? left : right;
}
代码解释
  • 递归过程:函数从根节点开始,先检查当前节点是否为目标节点。如果不是,则递归地在左子树和右子树中查找。
  • 结果处理:递归返回后,如果左右子树都有结果(即非null),则当前节点是LCA;否则,返回有结果的子树(表示LCA在该子树中)。
  • 正确性:算法保证了当p和q分布在当前节点的左右子树时,当前节点是LCA;如果p和q在同一个子树中,则递归返回该子树的结果。
  • 测试建议:在实际使用中,确保p和q在树中存在;可以通过构建二叉树并调用函数验证。
相关推荐
代码游侠几秒前
学习笔记——Linux字符设备驱动开发
linux·arm开发·驱动开发·单片机·嵌入式硬件·学习·算法
小王不爱笑1326 分钟前
LangChain4J 整合多 AI 模型核心实现步骤
java·人工智能·spring boot
西凉的悲伤7 分钟前
spring-boot-starter-validation使用注解进行参数校验
java·spring boot·参数校验·validation·注解校验参数
LucDelton19 分钟前
Java 读取无限量文件读取的思路
java·运维·网络
夹锌饼干29 分钟前
mysql死锁排查流程--(处理mysql阻塞问题)
java·mysql
小信丶38 分钟前
@EnableTransactionManagement注解介绍、应用场景和示例代码
java·spring boot·后端
m0_7369191040 分钟前
C++中的享元模式变体
开发语言·c++·算法
To Be Clean Coder1 小时前
【Spring源码】createBean如何寻找构造器(四)——类型转换与匹配权重
java·后端·spring
罗湖老棍子1 小时前
【 例 1】石子合并(信息学奥赛一本通- P1569)
数据结构·算法·区间dp·区间动态规划·分割合并
-孤存-1 小时前
SpringBoot核心注解与配置详解
java·spring boot·后端