最低公共祖先问题的求解
2016-08-30 21:28
190 查看
1.树的公共祖先问题
首先明确一下这里的公共祖先的概念。所谓公共祖先,就是两节点位于不同分支或者同一分支,最近的公共的父节点(说父节点不太准确,可能是祖父节点等)。
我们先不考虑算法,让我们自己找两个节点的最低公共祖先,我们应该是要按照路径找到两个节点,然后看两条路径的交点。很好,我们自下而上找交点是我们解决问题的思想。
变形1:我们可以从根节点遍历,若左子节点为根的左子树包含两个节点,则递归至左子树;若右子节点为根的右子树包含两个节点则递归至右子树。否则直接返回根节点。
注:此时树要是二叉搜索树,可以比较节点值的大小来进行变形1的计算。
若此时有指向父节点的指针,则从两个节点出发,问题转化为求两个链表的交点。
变形2:这个更加符合我们的思路,直接找到到两个节点的路径,求得路径的交点。
变形2的参考代码如下:
#include<iostream>
#include<list>
#include<vector>
using namespace std;
struct TreeNode
{
int value;
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(list<TreeNode *>&path1,list<TreeNode *>&path2)
{
list<TreeNode *>::iterator i1=path1.begin();
list<TreeNode *>::iterator i2=path2.begin();
TreeNode *node=NULL;
while(i1!=path1.end()&&i2!=path2.end())
{
if(*i1==*i2)
node=*i1;
i1++;
i2++;
}
return node;
}
TreeNode *GetLastCommonParent(TreeNode *pRoot,TreeNode *pNode1,TreeNode *pNode2)
{
if(pRoot==NULL||pNode1==NULL||pNode2==NULL)
return NULL;
list<TreeNode *>path1;
list<TreeNode *>path2;
GetNodePath(pRoot,pNode1,path1);
GetNodePath(pRoot,pNode2,path2);
return GetLastCommonNode(path1,path2);
}
代码是以多叉树的结构来写的。
之所以写这篇文章,是因为我们自己都会找最低公共祖先。但同时转化为程序、算法就显得有些吃力。其实这些还是人的解决方法一步步转化、提炼、优化。这个思路的过程:
自己的解决办法---->转化为算法
我之前有文章所说的不要自己凭空制造规则,所谓规则就是算法。我曾经为求简单,制造简单的规则是满足case较少的情况,但对于问题的解决没什么用。(自己制造的规则仅满足case1)。所以将你的解法概括为算法能够解决一类问题,每一步都很关键。但要大胆地迈出那一步,去不断总结,不断套路(动态规划),不断成长。
首先明确一下这里的公共祖先的概念。所谓公共祖先,就是两节点位于不同分支或者同一分支,最近的公共的父节点(说父节点不太准确,可能是祖父节点等)。
我们先不考虑算法,让我们自己找两个节点的最低公共祖先,我们应该是要按照路径找到两个节点,然后看两条路径的交点。很好,我们自下而上找交点是我们解决问题的思想。
变形1:我们可以从根节点遍历,若左子节点为根的左子树包含两个节点,则递归至左子树;若右子节点为根的右子树包含两个节点则递归至右子树。否则直接返回根节点。
注:此时树要是二叉搜索树,可以比较节点值的大小来进行变形1的计算。
若此时有指向父节点的指针,则从两个节点出发,问题转化为求两个链表的交点。
变形2:这个更加符合我们的思路,直接找到到两个节点的路径,求得路径的交点。
变形2的参考代码如下:
#include<iostream>
#include<list>
#include<vector>
using namespace std;
struct TreeNode
{
int value;
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(list<TreeNode *>&path1,list<TreeNode *>&path2)
{
list<TreeNode *>::iterator i1=path1.begin();
list<TreeNode *>::iterator i2=path2.begin();
TreeNode *node=NULL;
while(i1!=path1.end()&&i2!=path2.end())
{
if(*i1==*i2)
node=*i1;
i1++;
i2++;
}
return node;
}
TreeNode *GetLastCommonParent(TreeNode *pRoot,TreeNode *pNode1,TreeNode *pNode2)
{
if(pRoot==NULL||pNode1==NULL||pNode2==NULL)
return NULL;
list<TreeNode *>path1;
list<TreeNode *>path2;
GetNodePath(pRoot,pNode1,path1);
GetNodePath(pRoot,pNode2,path2);
return GetLastCommonNode(path1,path2);
}
代码是以多叉树的结构来写的。
之所以写这篇文章,是因为我们自己都会找最低公共祖先。但同时转化为程序、算法就显得有些吃力。其实这些还是人的解决方法一步步转化、提炼、优化。这个思路的过程:
自己的解决办法---->转化为算法
我之前有文章所说的不要自己凭空制造规则,所谓规则就是算法。我曾经为求简单,制造简单的规则是满足case较少的情况,但对于问题的解决没什么用。(自己制造的规则仅满足case1)。所以将你的解法概括为算法能够解决一类问题,每一步都很关键。但要大胆地迈出那一步,去不断总结,不断套路(动态规划),不断成长。
相关文章推荐
- 最低公共祖先问题
- Tarjan算法求解最近公共祖先问题
- 一颗普通的二叉树,如何寻找两个节点的最低公共祖先(发现的一个与算法无关的引用问题)
- 寻找二叉树中的最低公共祖先结点----LCA(Lowest Common Ancestor )问题(递归)
- 求解二叉查找树中的最低公共祖先结点
- 最低公共祖先问题(链表/树)
- 利用二叉树的非递归后序遍历求解最近公共祖先问题
- 最低公共祖先问题(LCA) 举一反三
- 面试题07 - 二叉树两节点的最低公共祖先 [树]
- 二叉树中的最近公共祖先问题
- Tarjan算法应用 (割点/桥/缩点/强连通分量/双连通分量/LCA(最近公共祖先)问题)
- 【HDU 2586 How far away ?】 邻接表+dfs+LCA(最近公共祖先问题)
- Java动态规划求解最长公共子串问题
- 树中两个节点的最低公共祖先
- 麒麟远创面试题3:二叉树中求两个节点的最低公共祖先节点
- 求二叉树中两个节点p,q的最低公共祖先节点
- 树的公共祖先问题LCA
- 二叉树两结点的最低公共祖先结点(一)
- LCA问题:求二叉树中任意两个节点的最近公共祖先
- 树中两个节点的最低公共祖先