力扣题236二叉树的最近公共祖先LCA_树lca力扣_xxyneymar的博客-程序员秘密

技术标签: 算法  力扣  leetcode  职场和发展  

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

百度百科中最近公共祖先的定义为:“对于有根树 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

1.递归。一个节点如果是两个节点的公共祖先的话,那么有两种情况:

        (1)这个节点的左子树包含其中一个节点,并且右子树包含另一个节点。

        (2)这个节点本身是其中一个节点,另一个节点在当前节点的左子树或右子树上。

   用一个boolean值来表示当前节点是否含有两个节点中一个,并且递归是从下往上进行的,找到的肯定就是最近的公共祖先。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    private TreeNode ans = null;//定义一个全局变量存储最近公共节点

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        dfs(root,p,q);
        return ans;
    }

    public boolean dfs(TreeNode root,TreeNode p,TreeNode q) {
        if(root == null){//如果节点为null,返回false
            return false;
        }

        boolean left = dfs(root.left,p,q);//判断左子树是否包含p或q
        boolean right = dfs(root.right,p,q);//判断右子树是否包含p或q
        //最近公共节点的条件
        //1.左子树包含其中一个,并且右子树包含另一个
        //2.当前根结点是其中一个,并且另一个在左子树上或者在右子树上
        if((left && right) || ((root.val == p.val || root.val == q.val) && (left || right))){
            ans = root;
        }
        //判断每个节点是否含有p或q
        return left || right || (root.val == p.val || root.val == q.val);
    }
}

        递归的优化:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if (root == null) {//当前根节点为null,返回null
            return null;
        }

        if (root == p || root == q) {//如果根节点是p或者q,那么最近公共祖先就是这个根节点
            return root;
        }

        //找到含有p或q的最小的子树
        TreeNode left = lowestCommonAncestor(root.left,p,q);
        TreeNode right = lowestCommonAncestor(root.right,p,q);

        if (left != null && right != null) {//说明分布在左右子树上,当前根节点就是最近的
            return root;
        }
        //说明p、q分布在同一侧子树上,就是非空的那个子树
        return left != null ? left : right;
    }
}

2.用哈希表存储所有节点的父节点,然后我们就可以利用节点的父节点信息从 p 结点开始不断往上跳,并记录已经访问过的节点,再从 q 节点开始不断往上跳,如果碰到已经访问过的节点,那么这个节点就是我们要找的最近公共祖先。

class Solution {
    Map<Integer,TreeNode> parent = new HashMap<>();//存储每个节点的父节点
    Set<TreeNode> visited = new HashSet<>();//存储从一个节点本身向上访问的节点路径

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        dfs(root);//把每个节点及其父节点的的关系存储到哈希表中

        while(p != null){//存储p从下往上的访问顺序
            visited.add(p);
            p = parent.get(p.val);
        }

        while(q != null){//从下往上q的访问顺序
            if(visited.contains(q)){//如果访问到p的访问路径中含有的节点,就是最近公共祖先,返回
                return q;
            }
            q = parent.get(q.val);
        }

        return null;
    }

    public void dfs(TreeNode root) {
        if(root.left != null){
            parent.put(root.left.val,root);
            dfs(root.left);
        }

        if(root.right != null){
            parent.put(root.right.val,root);
            dfs(root.right);
        }
    }
}

题源:力扣

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/xxyneymar/article/details/121785904

智能推荐

Centos7 搭建lnmp环境 (centos7+nginx+MySQL5.7.9+PHP7)_aotun7642的博客-程序员秘密

阿里云一台服务器出现问题!我估计是一键安装包环境的原因,所以打算重新搭建下环境!首先,当然是先做好快照!安全第一!对系统盘做更换系统操作,装上纯净版的centos。装好后,进入系统一、挂载数据盘df -h只有系统盘了,挂载上原来的数据盘fdisk -l看到数据盘了/dev/vdb1挂载上这个数据盘,mkdir /d...

git总结之3: git log 和git commit_tengxun28的博客-程序员秘密

什么是提交,怎么提交:    svn 下每次提交,版本号+1, git 由于是分布式,需要做到全球唯一,每次提交都生成一个新的版本号,可以统称为 commit id, 或 commit_id, 代指一次提交记录,生成hash值表示的字符串 bf8ee337fad87afa8ce6ff6c63d144fd2e4e3a68,  以后的命令操作,大致用前面6位或者7位,有时候用4位,就能单独表示

linux多线程下打开串口发送和接收数据_夏虫……的博客-程序员秘密

<br /> <br />1 启动线程1读串口<br />2 等待3秒后<br />3 启动线程2写串口,发送字符串后关闭<br />4 等待10秒<br />5 关闭两个线程<br /> <br /> <br /> <br />#include <pthread.h>#include <stdio.h>#include <sys/time.h>#include <string.h>#include<termios.h>#include<sys/stat.h>#include<fcn

UI设计实例|界面设计中,版式实战运用以及设计思路_通过案例思考构思法则在ui界面设计中的应用?_awayaya1的博客-程序员秘密

什么是用户体验界面版式设计版式设计是现代设计艺术的重要组成部分,是视觉传达的重要手段。表面上看,它是一种关于编排的学问;实际上,它不仅是一种技能,更实现了技术与艺术的高度统一,版式设计是现代设计者所必备的基本功之一。财务应用程序-概念v2app工作任务页企业银行业务应用程序的120多个移动UX原型制作流程图 Scheme Mobile Flowcharts智能家居APP通俗点解释,我们在做设计时需要有“条理性”的思维指导,因为人的眼睛或者大脑在短时间内无法处理大量

16.4.1 连接到 IMAP 服务器_大飞哥软件自习室的博客-程序员秘密

就像你需要一个 SMTP 对象连接到 SMTP 服务器并发送电子邮件一样,你需要个 IMAPClient 对象,连接到 IMAP 服务器并接收电子邮件。首先,你需要电子件服务提供商的 IMAP 服务器域名。这和 SMTP 服务器的域名不同。表 16-2列了几个流行的电子邮件服务提供商的 IMAP 服务器。表 16-2 电子邮件提供商及其 IMAP 服务器提供商 IMAP 服务...

随便推点

Java11常用类1:Object类、String类及相关、Date类_Bruce6379的博客-程序员秘密

Java常用类1:String类、StringBuffer、StringBuilder、Date类(Date、Time)、== 和 equals 的区别、 hashCode()与equals()

ADO.net之DataSet与DataReader_无名数的博客-程序员秘密

我们在.NET平台编程中ADO.net是经常要用的,而ADO.net中DataReader和DataSet又是我们主要用的2大核心组件。但是,很多ADO.net初学者都很难搞清楚,它们到底是什么,又怎么用?很容易被这二者给搞晕。越搞越乱,越搞越晕,最后感觉这块的东西太多,太复杂了,自己根本学不会,最后干脆就放弃了,这是一种很不好的现象。ADO.net这的东西你说多不多,就那几大对象,说少不少,每一

go语言切片详解,初始化、扩容、限容、底层_go 切片初始化_Aiky哇的博客-程序员秘密

原文链接:https://www.cnblogs.com/sparkdev/p/10704614.html切片(slice)是 Golang 中一种比较特殊的数据结构,这种数据结构更便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数 append() 来实现的,这个函数可以快速且高效地增长切片,也可以通过对切片再次切割,缩小一个切片的大小。因为切片的底层也是在连续的内存块中分配的,所以切片还能获得索引、迭代以及为垃圾回收优化的好处。本文将.

python 多线程笔记(3)-- 线程的私有命名空间_weixin_34315189的博客-程序员秘密

线程的私有命名空间实现:  threading_namespace =threading.local()import threadingimport timeimport randomthreading_namespace = threading.local() # 命名空间def print_country(): ...

车道检测模块_emgu 车道检测_Rachel-Zhang的博客-程序员秘密

车道检测问题一般由hough变换得到,但是这样得到的结果往往不尽人意,如图1所示:图1.直接进行hough变换检测直线那么我选取了一种基于概率模型和几何模型结合的方法进行检测。结果图分别如下图所示:步骤如下:首先进行图像增强or去噪:然后进行基于高斯概率模型的车道滤波:然后基于颜色的颜色空间转换:基于形态学的车道修

快门速度、光圈、ISO(感光度)_常用快门速度光圈iso搭配表_大大大__的博客-程序员秘密

摄影中最重要的三个设置就是快门速度、光圈和 ISO(感光度)。目录1. 快门速度1.1 快门速度的表示1.2快门速度和曝光2. 光圈2.1 光圈对曝光的影响2.2光圈对景深的影响3. ISO3.1 常用的 ISO 值1. 快门速度快门速度是指相机快门打开,将光线照射到相机传感器上的时间长度。本质上,就是相机花多长时间拍一张照片。快门速度主要有两个作用:改变相片的亮度、通过定格动作或运动模糊来创建戏剧性的效果。快门速度的存在是因为相机快门——它是相机传感器前面...

推荐文章

热门文章

相关标签