当前位置: 首页 > news >正文

<刷题笔记> 力扣236题——二叉树的公共祖先

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

                                           

题目解释:

我们以这棵树为例,来观察找不同的最近公共祖先有何特点:

思路一: 

除了第二种情况,最近公共祖先满足:一个节点在他的左边,一个节点在他的右边。

并且,其他公共祖先不满足这个条件,只有最近公共祖先满足这一点。 

所以我们可以利用这个逻辑来破题:从根节点开始往下查找,找到的第一个满足“p和q分别在他的左右两侧的节点”,就是要找的最近公共祖先。

先来特殊处理第二种情况:

然后涉及到最关键的步骤:

分别用bool值封装q和p找位置的函数,便于依次罗列出q和p对于当前节点的位置(是否满足一左一右)

实现IsInTree:

完整代码:

bool IsInTree(TreeNode* tree,TreeNode* k){if(tree==nullptr) return false;return tree==k|| IsInTree(tree->left,k)|| IsInTree(tree->right,k);}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//特殊处理本身存在爷孙或父子关系的情况if(root == p || root == q){return root;}//罗列出p和q是否存在的条件bool PInLeft = IsInTree(root->left,p);bool PInRight = !PInLeft;bool QInLeft = IsInTree(root->left,q);bool QInRight = !QInLeft;//分类讨论if((PInLeft && QInRight) || (QInLeft && PInRight)){return root;}else if(PInLeft && QInLeft){return lowestCommonAncestor(root->left,p,q);}else{return lowestCommonAncestor(root->right,p,q);}//return nullptr;}
};

但是实际运行速度并不理想: 运行速度几乎都要接近一秒了

这样操作的时间复杂度是O(N^2):

因为我们的树是一个毫无数据存放逻辑的任意形状的二叉树。所以,每一次去判断IsInTree都是把当前root下面的数据都遍历一遍,因此其本质其实是:第一遍从3开始查左查右,第二次从5开始查左查右,再从6开始查左查右......

如果遇到最坏的如下图一样的环境:

其时间复杂度是O(N^2)

当然,如果越接近完全二叉树的情形,时间复杂度越低,最理想能达到O(n)

                                       


思路二:

如果我们能根据找祖先的两个节点往回走,一切都会很好解决。

这样就变成了两条相交链表找交点。

使用前序查找+栈来找记录路径,然后再进行一次“两条相交链表找交点”

                                                

比如这张图,要找7,那么我们的路径应该记录为:3-5-2-7

在遇到6这样的错误的分支方向时,我们先将其入栈,发现他不对就出栈。

class Solution {
public:bool FindPath( stack<TreeNode*>& st , TreeNode* des , TreeNode* root){if(root==nullptr) {return false;}st.push(root);if(root == des){return true;}else if((!FindPath(st,des,root->left))&&(!FindPath(st,des,root->right))){st.pop();return false;}return true;}TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {stack<TreeNode*> q_path;stack<TreeNode*> p_path;FindPath(q_path,q,root);FindPath(p_path,p,root);while(q_path.size()!=p_path.size()){if(q_path.size()>p_path.size()) q_path.pop();if(p_path.size()>q_path.size()) p_path.pop();}while(q_path.top()!=p_path.top()){q_path.pop();p_path.pop();}return q_path.top();}
};

可以发现现在这种方法提升了不少速度: 

欢迎各位看官在评论区写出对这道题的其他解法。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • VS code 查看 ${workspaceFolder} 目录指代路径
  • nginx服务介绍
  • 密集行人数据集 CrowdHumanvoc和yolo两种格式,yolo可以直接使用train val test已经划分好有yolov8训练200轮模型
  • 全栈开发(四):使用springBoot3+mybatis-plus+mysql开发restful的增删改查接口
  • VSCode开发ros程序无法智能提示的解决方法(二)
  • 【计网面试真题】If-Modified-Since和Etag有什么区别
  • 【SSM-Day2】创建SpringBoot项目
  • 十、数字人IP应用方案
  • JAVA_17
  • 828 华为云征文|华为 Flexus 云服务器搭建萤火商城 2.0
  • 5、论文阅读:深水下的图像增强
  • 18 基于51单片机的心率体温监测报警系统(包括程序、仿真、原理图、流程图)
  • 基于vue框架的传染病人管理系统3w776(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
  • 【Java集合】LinkedList
  • vue一级、二级路由设计
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 【347天】每日项目总结系列085(2018.01.18)
  • 【前端学习】-粗谈选择器
  • Bootstrap JS插件Alert源码分析
  • emacs初体验
  • ES6之路之模块详解
  • Hibernate【inverse和cascade属性】知识要点
  • Javascript 原型链
  • java概述
  • miaov-React 最佳入门
  • nfs客户端进程变D,延伸linux的lock
  • PaddlePaddle-GitHub的正确打开姿势
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 初识MongoDB分片
  • 初探 Vue 生命周期和钩子函数
  • 干货 | 以太坊Mist负责人教你建立无服务器应用
  • 高性能JavaScript阅读简记(三)
  • 吴恩达Deep Learning课程练习题参考答案——R语言版
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • Linux权限管理(week1_day5)--技术流ken
  • ​香农与信息论三大定律
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (13)Hive调优——动态分区导致的小文件问题
  • (floyd+补集) poj 3275
  • (k8s)Kubernetes本地存储接入
  • (Oracle)SQL优化技巧(一):分页查询
  • (Python第六天)文件处理
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (附源码)基于SpringBoot和Vue的厨到家服务平台的设计与实现 毕业设计 063133
  • (贪心) LeetCode 45. 跳跃游戏 II
  • (转) ns2/nam与nam实现相关的文件
  • (转) 深度模型优化性能 调参
  • (转)C语言家族扩展收藏 (转)C语言家族扩展
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • .Net CF下精确的计时器
  • .net core + vue 搭建前后端分离的框架
  • .net 打包工具_pyinstaller打包的exe太大?你需要站在巨人的肩膀上-VC++才是王道
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .NET正则基础之——正则委托