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

news2024/9/22 21:22:57

目录

如果二叉树是二叉搜索树:

如果是普通的二叉树

【方法一】子树判断法

【方法二】路径确定

【方法三】递归


 面对此类型的公共祖先问题,可以分为以下几类情况讨论

如果二叉树是二叉搜索树:

a. 如果树是空,直接返回nullptr,没有最近公共祖先节点

b. 如果两个节点中有一个是根节点,最近公共祖先一定是根节点

c. 如果两个节点一个比根节点大,一个比根节点小,最近公共祖先一定是根节点

d. 如果两个节点都比根节点小,递归到根的左子树中查找

e. 如果两个节点都比根节点大,递归到根的右子树中查找

二叉搜索树的最近公共祖先_牛客题霸_牛客网

int lowestCommonAncestor(struct TreeNode* root, int p, int q ) {
    // write code here
    if(NULL == root)
    return -1;
    if(p<=root->val && q>=root->val || p>=root->val && q<=root->val)
    return root->val;
    else if(p<=root->val && q<=root->val)
    return lowestCommonAncestor(root->left, p, q);
    else
    return lowestCommonAncestor(root->right, p, q);
}

如果是普通的二叉树

力扣https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/

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

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

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

【方法一】子树判断法

解题思路:

        要求 :找到俩个结点的最近公共祖先,并返回该祖先结点

        参数: 一个具有二叉树序列的根节点、第一个查找值结点指针、第二个查找值结点指针。

想到可以通过判断结点为另一个结点子树的特性,如果subroot1为root的子树结点,那么该root节点即为该root的祖先,如果subroot2也同时为root的子树,那么该root即为其共同的公共祖先。

题目又要求找最近的公共祖先,那么只需要初始化一个指针,找到俩个结点的第一个公共祖先,并不断维护这个指针,使其一直指向俩结点的公共祖先。

    void dfs(TreeNode* root, TreeNode* p, TreeNode* q)
    {
        if(root==NULL)
        return;
        if(Issubtree(root, p) && Issubtree(root, q))
            res = root;
        dfs(root->left, p, q);
        dfs(root->right, p, q);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        dfs(root,p,q);
        return res;

如果root到了NULL的位置直接返回,如果p q同时为root的子树,那么更新res,使其指向该root结点,并持续不断进行遍历二叉树。

接着给出子树的函数

        子树不为空条件下可以省略下方俩步判断

    bool isSubtree(TreeNode* root, TreeNode* subRoot) {
        // if(root==NULL && subRoot==NULL)
        // return true;
        if(root==NULL && subRoot!=NULL)
        return false;
        // if(root!=NULL && subRoot==NULL)
        // return false;
        if(isSameTree(root,subRoot))
        return true;
        return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
    }

接着给出俩树相同判断

    bool isSameTree(TreeNode* p, TreeNode* q) {
        if(!p && !q)
        return true;
        if(!q || !p)
        return false;
        if(p->val == q->val)
            return isSameTree(p->left,q->left) && 
                    isSameTree(p->right, q->right);
        else
            return false;
    }

【方法二】路径确定

如果能够知道节点到根的路径,问题就解决了 获取节点pNode的路径,因为
公共祖先从下往上找,因此将路径中的节点保存在栈中
a. 如果是空树,直接返回
b. 将根节点入栈,如果根节点和pNode是同一个节点,该节点到根的路径找到,否则:
c. 递归在根节点的左子树中查找,如果找到,返回
d. 如果在根节点的左子树中未找到,递归到根节点的右子树中找
e. 如果右子树中没有找到,说明root一定不再路径中
 

1. 在二叉树中获取两个节点的路径

2. 如果两个路径中节点个数不一样,节点多的出栈,直到两个栈中元素相等

相等时:再比较两个栈顶是不是同一个节点,如果是,最近公共祖先找到, 如果不是,两个栈同时进行出栈,继续比较,直到找到为止
 

class Solution {
public:
	bool GetNodePath(TreeNode* pRoot, TreeNode* pNode, stack<TreeNode*>& path)
	{
		// 空树:直接返回
		if (nullptr == pRoot)
			return false;
		// 先将根节点放在路径中
		path.push(pRoot);
		// 如果根节点和pNode相等,路径找到
		if (pNode == pRoot)
			return true;
		// 如果根节点和pNode不相等,先递归在左子树中找,找到则退出
		bool isPath = false;
		if (isPath = GetNodePath(pRoot->left, pNode, path))
			return true;
		// 未找到时,再到根节点的右子树中找
		if (isPath = GetNodePath(pRoot->right, pNode, path))
			return true;
		// 如果左右子树中都没有找到,说明根节点不在路径中
		path.pop();
		return false;
	}
	TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
		// 如果是空树,不存在最近公共祖先节点
		if (nullptr == root)
			return nullptr;
		// 获取两个节点在二叉树中的路径,并保存在栈中
		stack<TreeNode*> pPath;
		stack<TreeNode*> qPath;
		GetNodePath(root, p, pPath);
		GetNodePath(root, q, qPath);
		// 找最近公共祖先
		size_t pSize = pPath.size();
		size_t qSize = qPath.size();
		TreeNode* pCommonAncestor = nullptr;
		while (pSize && qSize)
		{
			// 如果两个栈中元素不相等,长的先出栈,直到两个栈中元素相等
			if (pSize > qSize)
			{
				pPath.pop();
				pSize--;
			}
			else if (pSize < qSize)
			{
				qPath.pop();
				qSize--;
			}
			else
			{
				// 如果栈顶元素相等,即为最近公共祖先
				// 否则:两个栈同时出栈
				if (pPath.top() == qPath.top())
				{
					pCommonAncestor = pPath.top();
					break;
				}
				else
				{
					pPath.pop();
					qPath.pop();
					pSize--;
					qSize--;
				}
			}
		}
		return pCommonAncestor;
	}
};

【方法三】递归

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == nullptr || root == p || root == q) return root;
        TreeNode *left = lowestCommonAncestor(root->left, p, q);
        TreeNode *right = lowestCommonAncestor(root->right, p, q);
        if(left == nullptr && right == nullptr) return nullptr; // 1.
        if(left == nullptr) return right; // 3.
        if(right == nullptr) return left; // 4.
        return root; // 2. if(left != null and right != null)
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/133608.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式存储系统 Ceph 介绍与环境部署

文章目录一、概述二、Ceph 架构三、Ceph核心组件介绍四、Ceph 三种存储类型1&#xff09;块存储服务(RBD)2&#xff09;文件系统存储服务(CephFS)3&#xff09;对象存储服务(RGW)五、Ceph版本发行生命周期六、Ceph 集群部署1&#xff09;集群部署规划2&#xff09;前期准备1、关…

Python--让我们秀翻算法中的二进制

我相信大家在leetcode刷题或者更好的国外天梯刷题的时候应该经常能看到 **<<,>>,|,&**在我们的if里面构成了一个判断的条件. 然后在大家看不懂情况下就莫名其妙的把题目作对了!!! 所以我们准备持续的更新一下,二进制的用法. 大家要明白一个道理.一切的工具它…

Excel聚光灯--双箭头指示

实例需求&#xff1a;在工作表中核对数据时&#xff0c;虽然行列标题都会高亮显示&#xff0c;但是似乎并不明显&#xff0c;因此添加两个列标到活动单元格的箭头&#xff0c;以便于更好的定位。 选中单个单元格效果如下图所示。 选中多个单元格的效果如下图所示。 示例代码如…

51单片机——输出可调PWM

PWM控制在很多地方都会用到&#xff0c;比如使用PWM来控制电机的速度&#xff0c;使用PWM来生成想要的波形。 一、PWM PWM即脉冲宽度调制&#xff0c;在具有惯性的系统中&#xff0c;可以通过对一系列脉冲的宽度进行调制&#xff0c;来等效的获得所需要的模拟参量&#xff1b…

[JavaEE]线程的状态与安全

专栏简介: JavaEE从入门到进阶 题目来源: leetcode,牛客,剑指offer. 创作目标: 记录学习JavaEE学习历程 希望在提升自己的同时,帮助他人,,与大家一起共同进步,互相成长. 学历代表过去,能力代表现在,学习能力代表未来! 目录 1. 线程状态 1.1 观察线程的所有状态 1.2 线程的…

k-means算法进行数据分析应用

简介 kmeans算法又名k均值算法,K-means算法中的k表示的是聚类为k个簇&#xff0c;means代表取每一个聚类中数据值的均值作为该簇的中心&#xff0c;或者称为质心&#xff0c;即用每一个的类的质心对该簇进行描述。 其算法思想大致为&#xff1a;先从样本集中随机选取 k…

【王道操作系统】2.3.3 实现临界区进程互斥的硬件实现方法

实现临界区进程互斥的硬件实现方法 文章目录实现临界区进程互斥的硬件实现方法1.中断隐藏方法2.TestAndSet指令3.Swap指令1.中断隐藏方法 2.TestAndSet指令 执行TSL指令时&#xff0c;它的内部运转逻辑&#xff1a;假设lock现在为false&#xff0c;代表临界资源A空闲&#xff…

AssertionError: Torch not compiled with CUDA enabled解決方案

在執行pytorch代碼的時候&#xff0c;突然看到報錯 AssertionError: Torch not compiled with CUDA enabled 這說明了 1. 你pytoch确实安装了 2. 你安装的是cpu版本 作为验证&#xff0c;你可以在python编辑器输入下列代码 解决方案 首先&#xff0c;安装Nvidia toolkit su…

(深度学习快速入门)第二章:从线性神经网络入手深度学习(波士顿房价案例)

文章目录一&#xff1a;波士顿房价预测数据集说明二&#xff1a;Pytorch搭建模型&#xff08;1&#xff09;数据处理&#xff08;2&#xff09;网络结构&#xff08;3&#xff09;损失函数&#xff08;4&#xff09;优化方法&#xff08;5&#xff09;训练预测&#xff08;6&am…

pytorch应用(入门4)MLP实现MNIST手写数字分类

深层神经网络 前面一章我们简要介绍了神经网络的一些基本知识&#xff0c;同时也是示范了如何用神经网络构建一个复杂的非线性二分类器&#xff0c;更多的情况神经网络适合使用在更加复杂的情况&#xff0c;比如图像分类的问题&#xff0c;下面我们用深度学习的入门级数据集 M…

MyBatisPlus ---- 条件构造器和常用接口

MyBatisPlus ---- 条件构造器和常用接口1. wapper介绍2. QueryWrappera>例1&#xff1a;组装查询条件b>例2&#xff1a;组装排序条件c>例3&#xff1a;组装删除条件d>例4&#xff1a;条件的优先级e>例5&#xff1a;组装select子句f>例6&#xff1a;实现子查询…

dubbo源码实践-SPI扩展-自适应扩展机制

目录 1 前提必备知识 2 术语定义 3 自适应扩展机制的特点 4 扩展点实践 4.1 用户自定义自适应扩展 4.2 dubbo生成自适应扩展 4 自适应扩展类的用途 1 前提必备知识 具体的使用和原理就不说了&#xff0c;网上有人写的挺好的了。 可以参考&#xff1a; Dubbo SPI之自适…

【北京理工大学-Python 数据分析-1.1】

数据维度 维度&#xff1a;一组数据的组织形式 一维数据&#xff1a;由对等关系的有序或无序数据构成&#xff0c;采用线性组织形式。包括列表、集合和数组&#xff08;python中不常见&#xff0c;但在C和Java中比较常见&#xff09;类型。 列表&#xff1a;数据类型可以不同…

讲座笔记:Representation Learning on Networks

1 传统机器学习 传统机器学习需要进行很多的特征工程 我们希望模型自动学习特征&#xff0c;而不是用人为特征工程的方式1.1 目标 1.2 难点 graph更复杂&#xff0c;CNN和RNN很难直接应用 ——>复杂的拓扑结构&#xff08;不像CNN有网格的概念&#xff09;——>没有固定…

国家队入场,中国数字资产交易市场或将迎来新一轮“洗牌”

‍‍数据智能产业创新服务媒体——聚焦数智 改变商业数字化已经成为中国文化产业的催化剂&#xff0c;一大批文化资源在数字技术的赋能下焕发了崭新的生机。随着数字化的升级与科技进步&#xff0c;数字经济正在成为改变全球竞争格局的关键力量&#xff0c;各国家都争先出台相…

【微服务】Nacos 健康检查机制

目录 一、前言 二、注册中心的健康检查机制 三、Nacos 健康检查机制 四、临时实例健康检查机制 五、永久实例健康检查机制 六、集群模式下的健康检查机制 七、小结 &#x1f496;微服务实战 &#x1f496; Spring家族及微服务系列文章 一、前言 在前文中&#xff0c;…

使用 Helm 安装 MQTT 服务器-EMQX

EMQX ℹ️ Info: 使用 EMQX 通过 Helm3 在 Kubernetes 上部署 EMQX 4.0 集群 | EMQ emqx/deploy/charts/emqx at main-v4.4 emqx/emqx (github.com) emqx/values.yaml at main-v4.4 emqx/emqx (github.com) emqx/emqx-operator: A Kubernetes Operator for EMQ X Broker (git…

Arch Linux/Manjaro安装pycharm

首先换清华源以加快速度 &#xff08;已经换源的小伙伴可以跳过这一步&#xff09; 首先安装vim&#xff0c;用来编辑文件&#xff0c;已经安装过的可以跳过这一步。 sudo pacman -S vim 然后使用vim编辑配置文件 sudo vim /etc/pacman.d/mirrorlist 打开文件以后按inser…

Javaweb——第二章 Jsp和Servlet

目录 2.1 JSP概述 2.2 Servlet概述 2.3 jsp和servlet的区别和联系&#xff1a; ​编辑 2.4 Jsp的生命周期 2.4.1 JSP编译 2.4.2 JSP初始化 2.4.3 JSP执行 2.4.4 JSP清理 2.5 Servlet 2.5.1 Servlet的工作模式 2.5.2 Servlet创建方式 2.5.3 Servlet生命周期 2.1 JS…

JAVA之网络编程学习

文章目录一 java网络编程初识1.1 概述1.2 C/S 架构&B/S架构认识1.2.1 C/S架构1.2.2 B/S架构1.3 网络通信两个要素1.4 IP(Inet Adderss)1.5 InetAddress演示1.6 端口号1.7 InetSocketAddress使用1.8 网络通信协议二 TCP网络编程2.1 信息通信案例2.1.1 TcpClientDemo2.1.2 Tc…