面试题50:树中两个结点的最低公共祖先
来源:互联网 发布:贵金属手机交易软件 编辑:程序博客网 时间:2024/05/22 03:08
题目:输入树的两个结点,求它们的最低公共祖先。
第一种情况:当树是二叉树搜索树的时候
思路:根据二叉搜索树的性质,左子树都比父节点小,右子树结点值都比父节点大,从根节点开始便利二叉树,如果所给的两个结点都比当前结点的值小,则遍历当前结点的左子树,如果两个结点的值都比当前结点的值大就遍历当前结点的右子树,直到找出第一个介于两个结点之间的值就是最低公共祖先。
struct BTNode { int m_nValue; BTNode* m_pLeft; BTNode* m_pRight; }; BTNode * FindLCA(BTNode * root,BTNode * node1,BTNode * node2){if(root==NULL||node1==NULL||node2==NULL)return NULL;else{//如果当前结点的值大于两个结点的值,遍历左子树if(root->m_nValue>node1->m_nValue && root->m_nValue>node2->m_nValue){return FindLCA(root->m_pLeft,node1,node2);}//如果当前结点的值小于两个结点的值,遍历右子树else if(root->m_nValue<node1->m_nValue && root->m_nValue<node2->m_nValue){return FindLCA(root->m_pRight,node1,node2);}else{return root;}}}
第二种情况:树是一般的二叉树,但是带有指向父节点的指针
思路:如果带有指向父节点的指针,可以将两个结点看着是两个链表的头结点,然后根据求两个链表的第一个公共结点来求。
#include <iostream>using namespace std;struct CSNode{int m_nValue;CSNode* m_pParent;//指向父节点CSNode* m_pFirstChild;//左结点CSNode* m_pNextSibling;//右结点};//计算链表的长度int NodeCount(CSNode* pNode){assert(pNode);int nLen = 0;while(pNode){nLen++;pNode = pNode->m_pParent;}return nLen;}//寻找两个链表的公共结点CSNode* LCA(CSNode*& pFNode,CSNode*& pSNode){assert(pFNode && pSNode);int nDiff = 0;int nCountFir = NodeCount(pFNode);int nCountSec = NodeCount(pSNode);if (nCountFir > nCountSec){nDiff = nCountFir - nCountSec;while(nDiff){pFNode = pFNode->m_pParent;nDiff--;}}else{nDiff = nCountSec - nCountFir;while(nDiff){pSNode = pSNode->m_pParent;nDiff--;}}assert(pSNode && pFNode);while(pFNode != pSNode){pFNode = pFNode->m_pParent;pSNode = pSNode->m_pParent;}assert(pFNode);return pFNode;}//传入树的两个结点,查找它们的最低公共祖先CSNode* FindLCA(CSNode* pRoot,int nFirst,int nSec,CSNode*& pFNode,CSNode*& pSNode){//先序遍历树,查找这两个结点的位置if (!pRoot){return NULL;}if (pFNode && pSNode){return NULL;}//比较值if (pRoot->m_nValue == nFirst){pFNode = pRoot;}if (pRoot->m_nValue == nSec){pSNode = pRoot;}if (pFNode && pSNode){//两个结点就是两个链表的头结点,查找最低公共祖先return LCA(pFNode,pSNode);}//递归遍历树CSNode* pLCALeft = FindLCA(pRoot->m_pFirstChild,nFirst,nSec,pFNode,pSNode);CSNode* pLCARight = FindLCA(pRoot->m_pNextSibling,nFirst,nSec,pFNode,pSNode);return pLCALeft == NULL ? pLCARight : pLCALeft;}
代码来源:http://blog.csdn.net/insistgogo/article/details/9934153
第三种情况:既不是二叉搜索树也没有包含指向父节点的指针
思路:首先寻找从根节点到树中某一结点的路径,所以在遍历的时候需要辅助内存来保存路径。
1.首先从根节点开始遍历,遍历A,把A存放到路径中去,路径中只有一个A
2.遍历B,把B也放入路径中,此时路径为A-B
3.遍历D,把D放入路径中,此时路径为A-B-D
4.遍历F,把F存放到路径中,此时路径为A-B-D-F
5.F没有子节点,此路径不可能到达结点H,把F删除,变为A-B-D
6.遍历G,和结点F一样,这条路也不能到达H,所以仍然是A-B-D
7.由于D的所有子节点都已经遍历过,不可能到达H,所以将D也删除,变为A-B
8.遍历E,把E加入路径,变为A-B-E
9.遍历H,到达目标结点,A-B-E就是从根节点到达H所必须经过的路径
10.然后对F求必须经过的路径
11.找出两条路径中最后的公共结点
从根节点开始到输入的两个结点的两条,需要遍历两次树,每遍历一次的时间复杂度是O(n),得到的两条路径的长度在最差情况时是O(n),通常情况下两条路径的长度是O(logn)。
#include <iostream>#include <vector>#include <list>using namespace std;struct TreeNode { int m_nValue; std::vector<TreeNode*> m_vChildren; };bool GetNodePath(TreeNode *pRoot,TreeNode *pNode, list<TreeNode*> &path){if (pRoot=pNode){return true;}path.push_back(pRoot);bool found=false;vector<TreeNode*>::iterator i=pRoot->m_vChildren.begin();while(!found&&i<pRoot->m_vChildren.end()){found=GetNodePath(*i,pNode,path);++i;}if (!found){path.pop_back();}return found;}TreeNode* GetLastCommonNode(const list<TreeNode*>& path1, const list<TreeNode*>& path2){list<TreeNode*>::const_iterator i1=path1.begin();list<TreeNode*>::const_iterator i2=path2.begin();TreeNode* pLast=NULL;while(i1!=path1.end()&&i2!=path2.end()){if (*i1==*i2){pLast=*iterator;}i1++;i2++;}return pLast;}TreeNode* GetLastCommonParent(TreeNode* pRoot,TreeNode* pNode1,TreeNode* pNode2){if (pRoot==NULL||pNode1==NULL||pNode2==NULL){return NULL;}list<TreeNode*> path1;GetNodePath(pRoot,pNode1,path1);list<TreeNode*> path2;GetNodePath(pRoot,pNode2,path2);return GetLastCommonNode(path1,path2);}
代码来自:http://m.blog.csdn.net/blog/dgy610927/39081703
- 《剑指offer》面试题50 树中两个结点的最低公共祖先
- 面试题50:树中两个结点的最低公共祖先
- 《剑指Offer》学习笔记--面试题50:树中两个结点的最低公共祖先
- 【剑指offer】 面试题50: 树中两个结点的最低公共祖先
- 【剑指Offer学习】【面试题50:树中两个结点的最低公共祖先】
- 剑指offer之面试题50树中两个结点的最低公共祖先
- 剑指offer--面试题50:树中两个结点的最低公共祖先
- 剑指offer——面试题50:树中两个结点的最低公共祖先
- 剑指offer-面试题50-树中两个结点的最低公共祖先
- 剑指offer 面试题50 树中两个结点的最低公共祖先
- 面试题50. 树中两个结点的最低公共祖先结点
- 二叉树经典面试题3~树中两个结点的最低公共祖先
- 【剑指offer】 面试题50: 树中两个结点的最低公共祖先(二叉排序数)
- 树中两个结点的最低公共祖先50
- 剑指Offer面试题49字符串转整数,面试题50二叉树两个结点的最低公共祖先
- [剑指offer][面试题50]树中两个节点的最低公共祖先
- 剑指Offer:面试题50 树中两个节点的最低公共祖先
- 剑指offer 面试题50—树中两个节点的最低公共祖先
- UVa 11235 频繁出现的数值
- Openfire3.9.3源代码导入eclipse中开发配置教程
- iOS 开发库(iOS Developer Library)
- Adblock Plus的设置
- hdoj 3789 奥运排序问题
- 面试题50:树中两个结点的最低公共祖先
- solr的简单使用说明
- 删除编辑文件警告Swap file “…” already exists!
- VC实现文件拖放
- ios中摄像头/相册获取图片,压缩图片,上传服务器方法总结
- HttpServlet中的几个常用方法
- CIDR和NAT协议浅析
- CUDA 与 OpenCL 区别
- GDI+创建字体的方法