题目
树中两个节点的最低公共祖先
设计一个函数,输入两个树节点,求它们的最低公共祖先。树是最普通的树,不是二叉树。可以使用辅助内存
思路
1、使用两个链表,分别保存从根节点到输入的两个节点的路径,然后把问题转换成两个链表的最后公共节点。
2、
3、用前序遍历的方法来得到从根节点到H的路径的过程:遍历A,把A存到路径中;遍历到B,把B存到路径中,此时路径为A->B;遍历到D,把D存到路径中,此时路径为A->B->D;遍历到F,把F存到路径中,此时路径为A->B->D->F;F已经是叶子节点了,所以这条路径不可能到达节点H,于是把F从路径中删除,从D又遍历到G,路径为A->B->D->G。结果和遍历到F节点一样,这条路径同样也不能到达节点H。从路径中删除节点G,由于D的所有子节点都遍历过了,不可能到达节点H,因此D不在从A到H的路径中,把节点D从路径中删除,变成A->B。接着由B节点遍历到E节点,把E存放到路径中,遍历H,已经到达目标节点【这个过程其实就是之前的一道“在树中找到达某一输入节点的路径”的类型题】
4、每找到一个节点的路径,就需要遍历一遍树,遍历一次的时间复杂度是O(n)。于是得到两条路径的长度在最差情况是O(n)
#include<list>
#include<vector>
using std::vector;
using std::list;
struct TreeNode
{
int nValue;
vector<TreeNode*> childNodes;
};
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->childNodes.begin();
while (!found&&i < pRoot->childNodes.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 it1 = path1.begin();
list<TreeNode*>::const_iterator it2 = path2.begin();
TreeNode* pLast = nullptr;
while (it1 != path1.end() && it2 != path2.end())
{
if (*it1 == *it2)
pLast = *it1;
it1++;
it2++;
}
return pLast;//返回链表中最后一个相同的节点
}
TreeNode* GetLastCommonParent(TreeNode* pRoot, TreeNode* pNode1, TreeNode* pNode2)
{
if (pRoot == nullptr || pNode1 == nullptr || pNode2 == nullptr)
return nullptr;
list<TreeNode*> path1;
GetNodePath(pRoot, pNode1, path1);
list<TreeNode*> path2;
GetNodePath(pRoot, pNode2, path2);
return GetLastCommonNode(path1, path2);
}