目录

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

最近公共祖先I

最近公共祖先II

最近公共祖先III

最近公共祖先IV


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

1.对应letecode链接:

剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 - 力扣(LeetCode)

2.题目描述:

3.解题思路:

1.首先我们先判断根节点如果当前节点等于p或者q中的一个那么根节点就是p和q的最近公共祖先。

2.如果当前节点的值比p和q都要小那么就去左树上去找。

3.如果当前节点的值比p和q都要大那么就去右树上找

4.如果不是都大或者是都小的话说明当前节点就是p和q的最近公共祖先。

4.对应代码:

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {TreeNode*cur=root;while(cur){if(cur->val<p->val&&cur->val<q->val){cur=cur->right;}else if(cur->val>p->val&&cur->val>q->val){cur=cur->left;}else//说明cur是p和q的最近公共祖先{return cur;}}return NULL;}
};

最近公共祖先I

1.对应letecode链接:

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

2.题目描述:

3.解题思路:

首先我们先来看一个例子:

在上图中7和9的最近公共祖先是2.我们很直观的就看出来了,本题最简单的方法就是两个节点从自己出发一值往上走找到第一个相交的节点就是最近公共祖先。但是问题又来了本题中二叉树的节点当中没有父亲指针。是不是上面的方法就不行了呢?我们可以定义一个哈西表生key值对应的某个节点而val都应的是它的父亲,这样不就可以实现了吗?具体请看代码。

4.对应代码:

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {unordered_map<TreeNode*,TreeNode*>parent;//key为某个节点,val为其父亲。父亲表queue<TreeNode*>Q;//通过层序遍历生成父亲表Q.push(root);parent[root]=nullptr;while(!Q.empty()){auto node=Q.front();Q.pop();if(node->left){Q.push(node->left);parent[node->left]=node;}if(node->right){Q.push(node->right);parent[node->right]=node;}}//  父亲表生成完毕set<TreeNode*>path;while(p){path.insert(p);p=parent[p];//往上走}while(!path.count(q)){q=parent[q];//往上走;}return q;}
};

方法二:递归后序遍历

1.从根节点开始找判断根节点是否是p和q之中的一个如果是说明最近公共祖先就是当前的根节点root.

2.如果根节点没有找到则递归去左树和右树上去找。

3.我们使用leftRet和rightRet来接收来自左子树和右子树的结果,如果leftRet和rightRet都不为空说明左边和右边各一个那么此时根节点就是最近公共祖先。否则肯定是两个节点一边一个。此时我们只需要将不为空的那个返回即可。

4.对应代码:

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(!root||root==p||root==q){return root;}TreeNode* pqInLeft=lowestCommonAncestor(root->left,p,q);TreeNode*pqInRight=lowestCommonAncestor(root->right,p,q);//左右都不为空说明左边和右边各有一个if(pqInLeft&&pqInRight){return root;}return pqInRight?pqInRight:pqInLeft;}
};

最近公共祖先II

1.对应letecode链接:

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

2.题目描述

3.解题思路:

本题和上题的区别是本题p和q这两个节点有可能不在树上,就只有这一个区别。那么我们是不是只需要提前查找一个p和q这两个节点是否在树上如果不在直接返回nullptr。如果使用上题的逻辑就解决了。

4.对应代码:

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {if(!Find(root,q)||!Find(root,p)){//只要p和q有一个没有在树上就说明没有最近公共祖先return nullptr;}return _lowestCommonAncestor( root, p, q);}TreeNode* _lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){if(!root||root==p||root==q){return root;}auto leftRet=_lowestCommonAncestor(root->left, p, q);auto rightRet=_lowestCommonAncestor(root->right, p, q);if(leftRet&&rightRet){return root;}return leftRet?leftRet:rightRet;}bool Find(TreeNode*root,TreeNode*target){if(root==nullptr){return false;}if(root->val==target->val){//找到了return true;}bool leftRet=Find(root->left, target);//左树找到了if(leftRet){return true;}bool rightRet=Find(root->right,target);//右树找到了if(rightRet){return true;}//左右都没找到return false;}};

方法二:不检查节点是否存在

如果某个点x是p和q的祖先结点,情况1是x的左子树含有p和q或者右子树含有p和q,第二种情况是x本身就是p或q之一,而自己的左右子树中含有另外一个需要的值
dfs的过程的返回值的含义是以root为头结点的树中是否含有p或者q。dfs的是不断越来越深的遍历,ans更新的一定是祖先结点,随着深度加深最后更新的ans一定是最近公共祖先。

对应代码:

class Solution {
public:
TreeNode*ans=nullptr;TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {process(root, p, q);return ans;}bool process(TreeNode*root,TreeNode*p,TreeNode*q){if(root==nullptr){return false;}bool leftRet=process(root->left,p,q);bool rightRet=process(root->right,p,q);if(leftRet&&rightRet){ans=root;}//根节点的值有一个和root相等并且左子树和右子树要发现p和q其中的一个if((root->val==p->val||root->val==q->val)&&(leftRet||rightRet)){ans=root;}return p->val==root->val||q->val==root->val||leftRet||rightRet;}
};

最近公共祖先III

1.对应letecode链接

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

2.题目描述:

3.解题思路:

本题和第二题介绍的第一种方法非常的相似我们可以使用它来解决这道题(在这里就不重复了),我们让两个节点都往上走找到第一个相交的节点。这不就是链表相交问题吗?

不太清楚的老铁可以看一下我的博客。

4.对应代码

class Solution {
public:Node* lowestCommonAncestor(Node* p, Node * q) {Node*curP=p;Node*curQ=q;while(curP!=curQ){curP=curP?curP->parent:q;curQ=curQ?curQ->parent:p;}return curP;}
};

最近公共祖先IV

1.对应letecoede链接:

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

2.题目描述:

3.解题思路:

这题和上面这些题非常类似思路基本相同。依题意,nodes中的所有节点均存在于二叉树中
因而,{nodes中所有节点的最近公共祖先},可以弱化为{当前子树上的隶属于nodes中的所有节点的最近公共祖先},这样就无需考虑是否包含了nodes中的全部节点了。
1)若子树的root是nodes中的节点,则其必为该子树上隶属于nodes的所有节点的最近公共祖先。因为其本身就是该子树的根了(包含了当前子树的整个范围不能再往上了),且其自身隶属于nodes因而也不能再往下了(再往下就漏掉了root本身);
2)若root的左右子树上均存在nodes中的节点,则root就是最近公共祖先;
3)若nodes中的节点都存在于某个子树,则返回该子树上所有隶属于nodes中的节点的公共祖先即可;
4)若整个root子树上不存在nodes中的节点,则该子树上隶属于nodes中的节点的公共祖先就是nullptr。

4.对应代码:

class Solution {
public:TreeNode* lowestCommonAncestor(TreeNode* root, vector<TreeNode*> &nodes) {if(root==nullptr){return nullptr;}for(auto x:nodes){if(x==root){return root;}}TreeNode*leftRet=lowestCommonAncestor(root->left, nodes);TreeNode*righRet=lowestCommonAncestor(root->right, nodes);if(leftRet&&righRet){return root;}return leftRet?leftRet:righRet;}
};

最近公共祖先问题你真的学会了吗?相关推荐

  1. luogu P3379 【模板】最近公共祖先(LCA)

    lca最近公共祖先,是指两个点最近的祖先节点:求lca我知道的有三种倍增, st表,tarjan,我要介绍的是倍增,我才不会告诉你我只会这一个. 话说我学lca可真的路途曲折,在qbxt,lcy da ...

  2. 与图论的邂逅05:最近公共祖先LCA

    什么是LCA? 祖先链 对于一棵树T,若它的根节点是r,对于任意一个树上的节点x,从r走到x的路径是唯一的(显然),那么这条路径上的点都是并且只有这些点是x的祖先.这些点组成的链(或者说路径)就是x的 ...

  3. 代码随想录算法训练营第22天 二叉树 java :235. 二叉树的最近公共祖先 701.二叉搜索树中的插入操作 450.删除二叉搜索树中的节点

    文章目录 LeetCode 236. 二叉树的最近公共祖先 题目讲解 思路 LeetCode 701.二叉搜索树中的插入操作 题目讲解 思路 LeetCode 450.删除二叉搜索树中的节点 题目讲解 ...

  4. 有一个1亿结点的树,已知两个结点, 求它们的最低公共祖先!

    对该问题,分为如下几种情形讨论: 情形一: 假如该树为二叉树,并且是二叉搜索树, 依据二叉搜索树是排过序的, 我们只需要从树的根结点开始,逐级往下,和两个输入的结点进行比较. 如果当前结点的值比两个结 ...

  5. 二叉树:最近的公共祖先 Lowest Common Ancestor of a Binary Tree

    已知二叉树,求二叉树中给定的两个节点的最近公共祖先. 最近公共祖先: 两节点v与w的最近公共祖先u,满足在树上最低(离根最 远),且v,w两个节点都是u的子孙. 如上二叉树,6和8号节点的公共祖先有4 ...

  6. Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)...

    转载自:http://hi.baidu.com/lydrainbowcat/blog/item/2194090a96bbed2db1351de8.html 基本概念: 1.割点:若删掉某点后,原连通图 ...

  7. LeetCode实战:二叉树的最近公共祖先

    背景 为什么你要加入一个技术团队? 如何加入 LSGO 软件技术团队? 我是如何组织"算法刻意练习活动"的? 为什么要求团队的学生们写技术Blog 题目英文 Given a bin ...

  8. LeetCode实战:二叉搜索树的最近公共祖先

    背景 为什么你要加入一个技术团队? 如何加入 LSGO 软件技术团队? 我是如何组织"算法刻意练习活动"的? 为什么要求团队的学生们写技术Blog 题目英文 Given a bin ...

  9. 0x63.图论 - 树的直径与最近公共祖先

    目录 一.树的直径(Diameter) 1.树形DP求树的直径 2.两次BFS/DFS求树的直径 1.POJ 1985.Cow Marathon(DFS求树的直径模板题) 2.AcWing 350. ...

最新文章

  1. 关于CSDN不给任何通知强制关闭我的6年博客,我深表痛心
  2. Redis的快照与AOF
  3. java获取web.xml 参数_解析web.xml中在Servlet中获取context-param和init-param内的参数
  4. Linux下设计并发队列
  5. Win7 路由上网DNS服务器ping不通的解决方法
  6. 微架构设计:微博计数器的设计
  7. Django从理论到实战(part32)--外键删除
  8. SAP云平台点了subscription菜单后的roundtrip
  9. FileBeat + Pipeline 解析日志 保存至ElasticSearch(实战)
  10. 图解高性能服务器开发两种模式,第四章 NETTY高性能架构设计
  11. Webpack3 从入门到放弃
  12. 移动开发的跨平台技术发展史 | 技术头条
  13. Oralce weblogic 11g 安装部署使用手册
  14. PTA—比较大小(C语言)
  15. HCIE Security 防火墙用户管理与认证 备考笔记(幕布)
  16. webstorm注释写出的提示
  17. 自适应机器人:定义工业机械臂的未来
  18. PV,UV,VV,IP
  19. JavaScript代码优化 --- 长期更新
  20. 2021知识付费、流量变现小程序源码系统搭建安装教程,一个小白都可以日入过千的项目。

热门文章

  1. 德国电信5G网络已覆盖德国一半人口,提前实现今年目标!
  2. Hblock盘活企业级存储市场
  3. 【22考研】计算机择校信息库!近百所高校21计算机考研数据汇总!(持续更新中)
  4. 博士win7风格包_异常可爱,民间团队与暴雪合作推出《星际争霸》卡通材质包...
  5. 文件快速拷贝工具FastCopy 使用教程
  6. 5GC中网络切片NSSAI详解
  7. C语言字符串头文件string.h中的strlen,strcat,strcpy,strncpy,strcmp,strlwr,strupr函数
  8. 看懂RTK定位,这一篇就够啦!
  9. spring boot web程序发布到金蝶中间件
  10. python中的findall函数_关于Python正则表达式 findall函数问题详解