二叉树两个节点的公共节点
转自:http://blog.csdn.net/hhygcy/article/details/4660362
很流行的一个问题,常见于各种面试中,http://fayaa.com/tiku/view/16/ 这里有一个很好的汇总.
找寻二叉树中两个节点的公共父节点中最近的那个节点
情况1. 节点只有left/right,没有parent指针,root已知 情况2. root未知,但是每个节点都有parent指针 情况3. 二叉树是个二叉查找树,且root和两个节点的值(a, b)已知 |
虽然情况一是第一个情况,但是看上去比较复杂,我们放到最后来说,先从第二个情况开始说。
10
/ /
6 14
/ / / /
4 8 12 16
/ /
3 5
画一个二叉树来做例子。如果我们要找3和8这两个节点的公共父亲节点,我们的做法是首先找到3到根节点的路劲,然后找到8到根节点的路径。
10
// /
6 14
/ / / /
4 8 12 16
/ /
3 5
3的路径用红色表示,8的用绿色表示,可以看到, 这里的问题实际上是另一个我们熟知的问题,有2个相交的单链表,找出它们的相交点!
只要把这个二叉树的图片倒过来看,或者把脖子倒过来看就知道了:)那个方法也是传统的求出linkedList A的长度lengthA, linkedList B的长度LengthB。然后让长的那个链表走过abs(lengthA-lengthB)步之后,齐头并进,就能解决了。
- int getLength (bstNode* pNode)
- {
- int length = 0;
- bstNode* pTemp = pNode;
- while (pTemp)
- {
- length ++ ;
- pTemp = pTemp->pParent;
- }
- return length;
- }
- bstNode* findLCACase2(bstNode* pNode1, bstNode* pNode2)
- {
- int length1 = getLength(pNode1);
- int length2 = getLength(pNode2);
- // skip the abs(length1-length2)
- bstNode* pIter1 = NULL;
- bstNode* pIter2 = NULL;
- int k=0;
- if (length1>=length2)
- {
- bstNode* pTemp = pNode1;
- while (k++<length1-length2)
- {
- pTemp = pTemp->pParent;
- }
- pIter1 = pTemp;
- pIter2 = pNode2;
- }
- else
- {
- bstNode* pTemp = pNode1;
- while (k++<length2-length1)
- {
- pTemp = pTemp->pParent;
- }
- pIter1 = pNode1;
- pIter2 = pTemp;
- }
- while (pIter1&&pIter2&&pIter1!= pIter2)
- {
- pIter1 = pIter1->pParent;
- pIter2 = pIter2->pParent;
- }
- return pIter1;
- }
自己写了个代码,总觉得有些拖沓冗余,希望有缘人看到文章之后能帮我改写的更和谐一些。
还是原来这个图,情况三,如果是个二叉搜索树,而且root和a, b已知,我们这个case假设a,b=3,8。从知道根这个条件我们很自然联想到递归(当然不递归也可以)地往下找。关键是收敛条件,什么情况下可以判断出当然检查的这个节点是最近父亲节点呢?其实从这个例子已经可以看出一些端倪了,如果当前访问的节点比a,b来的都小,肯定不行。如果比a,b都大,也不行。那也就是说,这个节点只有在a<=node<=b的区间内才成立(我们假定a<b这里)。这样的问题,网上广为流传着类似的代码:
- bstNode* findLCACase3(bstNode* pNode, int value1, int value2)
- {
- bstNode* pTemp = pNode;
- while (pTemp)
- {
- if (pTemp->data>value1 && pTemp->data>value2)
- pTemp = pTemp->pLeft;
- else if(pTemp->data<value1 && pTemp->data<value2)
- pTemp = pTemp->pRight;
- else
- return pTemp;
- }
- return NULL;
- }
好,前面的问题都解决了,我们再回过头来看第一个情况,只有ROOT和left, right节点,没有parent也不是排序树,怎么办?网络上也流传着很多所谓的LCA,RMQ算法,我们不暇找个最合适的,尤其是在面试的时候,特定时间空间下你很难写出一个逻辑非常复杂的东西(比如你会在面试的时候去实现一个Suffix Tree还是用动态规划来求最长公共子串,哪怕效率不同,我也选择动态规划:))。所以这里,碰到类似的问题的时候,我选择简单的记录找到node1和node2的路径,然后再把它们的路径用类似的情况二来做分析,比如还是node1=3,node2=8这个case.我们肯定可以从根节点开始找到3这个节点,同时记录下路径3,4,6,10,类似的我们也可以找到8,6,10。我们把这样的信息存储到两个vector里面,把长的vector开始的多余节点3扔掉,从相同剩余长度开始比较,4!=8, 6==6, coooool,我们找到了我们的答案。下面的代码完全按照这个思路写成
- #include <vector>
- bool nodePath (bstNode* pRoot, int value, std::vector<bstNode*>& path)
- {
- if (pRoot==NULL) return false;
- if (pRoot->data!=value)
- {
- if (nodePath(pRoot->pLeft,value,path))
- {
- path.push_back(pRoot);
- return true;
- }
- else
- {
- if (nodePath(pRoot->pRight,value,path))
- {
- path.push_back(pRoot);
- return true;
- }
- else
- return false;
- }
- }
- else
- {
- path.push_back(pRoot);
- return true;
- }
- }
- bstNode* findLCACase1(bstNode* pNode, int value1, int value2)
- {
- std::vector<bstNode*> path1;
- std::vector<bstNode*> path2;
- bool find = false;
- find |= nodePath(pNode, value1, path1);
- find &= nodePath(pNode, value2, path2);
- bstNode* pReturn=NULL;
- if (find)
- {
- int minSize = path1.size()>path2.size()?path2.size():path1.size();
- int it1 = path1.size()-minSize;
- int it2 = path2.size()-minSize;
- for (;it1<path1.size(),it2<path2.size();it1++,it2++)
- {
- if (path1[it1]==path2[it2])
- {
- pReturn = path1[it1];
- break;
- }
- }
- }
- return pReturn;
- }
这段代码经历了大概30分钟的修改和debug,然后才逐渐稳定下来,真的很难想象如果是在面试的环境下,在纸笔之上会有如何的表现,可能真是只有天知道了。
二叉树两个节点的公共节点相关推荐
- 剑指offer之求两个链表的第一个公共节点
1 问题 输入两个链表,找出它们的第一个公共结点. 含有公共节点的两个链表的结构类似于下图中的链表: 1 -> 2 -> 3 -> 4 ->5 2 -> 4 ->5 ...
- java中获取链表的第一个节点,两个链表中的第一个公共节点(java)
题目描述: 输入两个链表,找出它们的第一个公共结点. 分析: 思路一:暴力解法,强烈不建议! 遍历第一个链表的每个节点,同时每次都遍历一遍另一个链表,看是否有节点和这个节点相同,如果有相同节点就是公共 ...
- 剑指Offer+第37题+两个链表的第一个公共节点+java
题目:输入两个链表,找出它们的第一个公共结点. 面试的时候碰到这道题,很多应聘者的第一反应就是蛮力法:在第一链表上顺序遍历每个结点,没遍历到一个结点的时候,在第二个链表上顺序遍历每个结点.如果在第二个 ...
- 【IT笔试面试题整理】寻找二叉树两节点的最近的公共祖先
[试题描述] 求二叉树中任意两个节点的最近公共祖先也称为LCA问题(Lowest Common Ancestor). 二叉查找树 如果该二叉树是二叉查找树,那么求解LCA十分简单. 基本思想为:从树根 ...
- 数据结构-寻找二叉树两节点的最近公共祖先(Java)
寻找最近公共祖先 题目 给定一个二叉树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:"对于有根树 T 的两个节点 p.q,最近公共祖先表示为一个节点 x,满足 ...
- 二叉树两个节点最近公共祖先的解法
假设有一个二叉树.根节点为TreeNode root.p节点和 q节点均在二叉树中.求p和q的最近公共祖先节点. 优雅的递归解法: 对于这个问题, 我们定义一个函数.但是这个函数扩充这个问题的定义 p ...
- 寻找二叉树两个结点的最低共同父节点
寻找二叉树两个结点的最低共同父节点 题目:二叉树的结点的定义如下: struct TreeNode {int m_nValue;TreeNode *m_pLeft;TreeNode *m_pRight ...
- 【Java】剑指 Offer 52. 两个链表的第一个公共节点
题目 :输入两个链表,找出它们的第一个公共节点. 算法思路 : 首先我们要明确,两个链表相交,是Y形状的 两个链表相交,是next域相同 因为两个单链表的长度是不一样的,所以我们需要让长的那个链表,引 ...
- 算法------ 两个链表的第一个公共节点
题目: 输入两个链表,找出它们的第一个公共节点. 如下面的两个链表: 在节点 c1 开始相交. 注意: 如果两个链表没有交点,返回 null. 在返回结果后,两个链表仍须保持原有的结构. 可假定整个链 ...
最新文章
- redis延迟队列 实现_灵感来袭,基于Redis的分布式延迟队列(续)
- pytorch 笔记:tensorboardX
- Java数三退一问题代码_数三退一问题算法(Java)
- 【Mail】telnet收发邮件过程
- 约瑟夫环(丢手绢问题)
- 蔡崇信与马云的 20 年
- Log4net日志记录包
- 前端特效-霓虹灯按钮
- 分类信息采集发布采集器软件
- Windows 10 Enterprise LTSC 2019 (x64) 版本 (安装+激活+添加系统邮箱)
- 微型计算机的性能主要由微处理器的什么,微型计算机的性能主要由微处理器的什么决定...
- 关于D3D中AGP显存,内存,显存三种内存的解释
- assimp批量转模型_IGS模型批量转换成STL模型
- 中国计算机科学院士,盘点!获奖者中,84位院士、10位国家最高科学技术奖得主,高校科学家表现出色...
- Win10安装Kali子系统
- 机器学习 逻辑回归算法应用案例
- 吉特仓库管理系统-ORM框架的使用
- SQL 中的LTRIM()和RTTIM()的用法
- 纤亿通带你去看空分复用光纤技术突破
- Win炫酷实用快捷键及触控板手势
热门文章
- 我的Java教程,不断整理,反复学习,记录着那些年大学奋斗的青春
- 直播预告 | AAAI 2022论文解读:融入知识图谱的分子对比学习
- 深圳招聘 | 元象唯思:决策AI研发工程师、NLP算法工程师(可实习)
- FewRel 2.0数据集:以近知远,以一知万,少次学习新挑战
- 如何独立实现一个基于知识图谱的问答系统
- 和49支战队瓜分600万奖金,这场史上奖金最多的AI大赛到底比什么?
- 二维计算几何基础知识
- ffmpeg 声音参数_ffmpeg转换参数和压缩输出大小的比率
- excel 两组数据交点_Python 自动化测试(四):数据驱动
- oracle protocol=beq 不可用,学习笔记:Oracle数据库坏块 深入研究obj$坏块导致exp/expdp不能执行原因...