二叉树的最近公共祖先,二叉搜索树的最近公共祖先(同一个思路)

目录

  • 二叉树的最近公共祖先
    • 方法一(时间复杂度O(N^2))
    • 方法二(时间复杂度O(N))
  • 二叉搜索树的最近公共祖先

二叉树的最近公共祖先


题目链接
  二叉树的最近公共祖先
  给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
  百度百科中最近公共祖先的定义为:“对于有根树 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 。因为根据定义最近公共祖先节点可以为节点本身

方法一(时间复杂度O(N^2))

给出一颗二叉树,再给出两个节点,p和q,且都在这颗二叉树中。
分三种情况
  情况1:p节点和q节点都在左子树,此时最近公共祖先也在左子树,继续分情况讨论
  情况2:p节点和q节点都在右子树,此时最近公共祖先也在右子树,续分情况讨论
  情况3:p节点和q节点一个在左子树,一个在右子树,此时这颗树的根就是最近公共节点
  特殊情况:如果p节点或者q节点其中一个为根节点,此时最近公共祖先就是根节点
采用递归,分解子问题

在这里插入图片描述
在这里插入图片描述

解题的本质思路就是递归调用解决子问题,将原问题划分为子问题

class Solution {
public:bool Find(TreeNode* root, TreeNode* val){if (root == NULL)return false;return root == val || Find(root->left, val) || Find(root->right, val);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//判断特殊情况,根节点为空if (root == NULL)return NULL;//特殊情况,p节点或者q节点其中一个为根节点,此时最近公共祖先就是根节点if (root == p || root == q)return root;//用来判断p和q在左右子树位置的变量bool pInLeft, pInRight, qInLeft, qInRight;pInLeft = Find(root->left, p);pInRight = !pInLeft;qInLeft = Find(root->left, q);qInRight = !qInLeft;if(pInLeft && qInLeft){//情况1:p和q都在左子树,递归调用根节点的左子树return lowestCommonAncestor(root->left,p,q);}else if(pInRight&& qInRight){//情况2:p和q都在右子树,递归调用根节点的右子树return lowestCommonAncestor(root->right,p,q);}else{//p和q,一个在左子树,一个在右子树,此时根节点为最近公共祖先return root;}}
};

方法二(时间复杂度O(N))

找路径法,将二叉树的p节点和q节点路径记录下来,转化为链表查找公共节点问题

思路,通过遍历二叉树的方法将p和q节点的路径纪录到两个栈中,
分情况讨论,查找p节点:不管什么情况先将节点入栈,判断刚入的节点是否为p节点,如过不是p节点,在p的左子树中查找,左子树没有查到去右子树中查,如果右子树也没有查到,将此节点出栈,直至找到p节点。q节点同理

代码:

class Solution {
public:bool FindPath(TreeNode* root,TreeNode* x,stack<TreeNode*>& path){//访问到空节点,返回falseif(root==nullptr)return false;//不管什么情况,先将当前节点入栈path.push(root);//判断当前节点是否为要查找节点if(root==x)return true;//递归左子树查找if(FindPath(root->left,x,path)){return true;}//递归右子树查找if(FindPath(root->right,x,path)){return true;}//左右子树以及根节点都不是要查找的节点,则将该节点出栈path.pop();return false;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {stack<TreeNode*> ppath; //记录p节点路径的栈FindPath(root,p,ppath);stack<TreeNode*> qpath; //记录q节点路径的栈FindPath(root,q,qpath);//将快的路径先走while(ppath.size()>qpath.size())ppath.pop();while(ppath.size()<qpath.size())qpath.pop();//第一个相同的节点就是最近公共祖先while(ppath.top()!=qpath.top()){ppath.pop();qpath.pop();}return qpath.top();}
};

二叉搜索树的最近公共祖先


题目链接
  二叉搜索树的最近公共祖先
  给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。
  百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
  例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5]

实例1:
在这里插入图片描述

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

实例2:

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

思路同上,不过二叉树的最近公共祖先需要先寻找p和q的位置进行递归调用,
由于二叉搜索树的特殊,我们不需要再手动查找p和q的位置,只需进行判断大小即可,二叉搜索树的性质,根节点的左子树元素比根节点小,根节点的左子树元素比根节点大。

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(root==NULL)return NULL;if(p==root||q==root)return root;if(p->val>root->val&&q->val>root->val){//都在右子树return lowestCommonAncestor(root->right,p,q);}else if(p->val<root->val&&q->val<root->val){//都在左子树return lowestCommonAncestor(root->left,p,q);}else{//一个在左,一个在右return root;}}
};

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[BUUCTF]-PWN:babyfengshui_33c3_2016解析

又是一道堆题&#xff0c;先看保护 关键信息是32位&#xff0c;没开pie 直接看ida 大致是alloc创建堆块&#xff0c;free释放堆块&#xff0c;show查看堆块内容&#xff0c;fill填充堆块内容 其他的都没啥关键的要讲&#xff0c;但alloc那里非常需要解析一下 解释如上图 再具…

网站将http升级到https大概要多少费用

随着网络安全意识的不断提升&#xff0c;越来越多的网站正从传统的HTTP协议转向更安全的HTTPS协议。这一转变的核心在于部署SSL&#xff08;Secure Sockets Layer&#xff09;或TLS&#xff08;Transport Layer Security&#xff09;证书&#xff0c;以实现数据加密传输&#x…

phar反序列化漏洞

基础&#xff1a; Phar是一种PHP文件归档格式&#xff0c;它类似于ZIP或JAR文件格式&#xff0c;可以将多个PHP文件打包成一个单独的文件&#xff08;即Phar文件&#xff09;。 打包后的Phar文件可以像普通的PHP文件一样执行&#xff0c;可以包含PHP代码、文本文件、图像等各…

微信小程序(十八)组件通信(父传子)

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.组件属性变量的定义 2.组件属性变量的默认状态 3.组件属性变量的传递方法 解释一下为什么是父传子&#xff0c;因为组件是页面的一部分&#xff0c;数据是从页面传递到组件的&#xff0c;所以是父传子&#xf…

SpringMVC第六天(拦截器)

概念 拦截器(Interceptor)是一种动态拦截方法调用的机制&#xff0c;在SpringMVC中动态拦截控制器方法的执行 作用&#xff1a; 在指定的方法调用前后执行预先设定的代码 阻止原始方法的执行 拦截器与过滤器的区别 归属不同&#xff1a;Filter属于Servlet技术&#xff0c;I…

k8s从初识到上天系列第二篇:kubernetes的组件和架构

&#x1f609;&#x1f609; 欢迎加入我们的学习交流群呀&#xff01; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring、SpringSecurity、Docker、Grpc、各种MQ、Rpc、SpringCloud等等很多应用和源码…

UDF学习(五)FLUENT UDF-DEFINE_INIT宏和DEFINE_DELTAT宏和DEFINE_ADJUST宏

FLUENT UDF-DEFINE_INIT宏 以此为例&#xff1a; DEFINE_INIT(init,domain)//一般格式 #include"udf.h" DEFINE_INIT(init,domain) { cell_t c; Thread *thread; real xc[ND_ND],x,y; thread_loop_c(thread,domain) { begin_c_loop(c,thread) } C_CENTROID(xc,c,t…

【C++】C++ 入门 — 命名空间,输入输出,函数新特性

C 1 前言2 命名空间2.1 概念引入2.2 开始使用2.3 投入应用 3 输入与输出3.1 基础知识3.2 开始使用3.3 注意局限 4 函数新特性4.1 缺省参数4.1.1 开始使用4.1.2 注意事项 4.2 函数重载4.2.1 开始使用4.2.2 如何实现 Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下…

Python算法题集_接雨水

本文为Python算法题集之一的代码示例 题目42&#xff1a;接雨水 说明&#xff1a;给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1]…

银行数据仓库体系实践(11)--数据仓库开发管理系统及开发流程

数据仓库管理着整个银行或公司的数据&#xff0c;数据结构复杂&#xff0c;数据量庞大&#xff0c;任何一个数据字段的变化或错误都会引起数据错误&#xff0c;影响数据应用&#xff0c;同时业务的发展也带来系统不断升级&#xff0c;数据需求的不断增加&#xff0c;数据仓库需…

HBase入门:运行机制

文章目录 HBase 系统架构客户端ZooKeeper 服务器Master 主服务器Region 服务器 Region 服务器工作原理用户读写数据的过程缓存的刷新StoreFile合并 Store 的工作原理HLog 的工作原理 HBase 系统架构 HBase 的系统架构包括客户端、ZooKeeper 服务器、Master 主服务器、Region服…

Liunx基础-----------------------第十六章网站服务

一、概念 UI的转变&#xff1a;B/S框架 HYML&#xff1a;超文本标记语言 网页&#xff1a;使用HTML&#xff0c;PHP&#xff0c;JAVA语言格式书写的文件 主页&#xff1a;网页中呈现用户的第一个页面 网站&#xff1a;多个网页组合而成的一台网站服务器 URL&#xff1a;统…