题型1.若树为二叉搜索树,则从根节点开始遍历,第一个在两个输入结点值之间的结点即为最低公共祖先
题型2.若为普通树,如果结点中有指向父结点的指针,那么该问题就变成了求两个链表的第一个公共结点问题
题型3.若为普通树,且结点中没有指向父结点的指针*/
/************************************************************************/
//针对题型3的三种解法
//解法一:需要辅助空间(需要两个链表分别存储从根节点到两个输入结点之间的路径,转而求两个链表的第一个公共结点问题
bool GetListofNode(TreeNode* head, TreeNode* node, vector<TreeNode*> &vecNode)
{
bool bFind=false;
if (head==NULL)
return false;
vecNode.push_back(head);
if (head==node)
return true;
if (head->left)
bFind=GetListofNode(head->left,node,vecNode);
if (!bFind)
{
if (head->right)
{
bFind = GetListofNode(head->right,node,vecNode);
}
}
if (!bFind)
vecNode.pop_back();
return bFind;
}
TreeNode* FindFirstCommonnode(TreeNode* Head, TreeNode* node1, TreeNode* node2)
{
if (Head==NULL || node1==NULL || node2==NULL)
return NULL;
TreeNode* pret = NULL;
vector<TreeNode*> vecNode1, vecNode2;
if(GetListofNode(Head,node1,vecNode1) && GetListofNode(Head,node2,vecNode2))//获得从根节点开始到两个输入结点的路径
{
vector<TreeNode*>::iterator it1 = vecNode1.begin();
vector<TreeNode*>::iterator it2 = vecNode2.begin();
while(it1!=vecNode1.end() && it2!=vecNode2.end())
{
if (*it1==*it2)
pret=*it1;
else
return pret;//不相等,则返回
it1++;
it2++;
}
}
return pret;
}
//解法二:不利用辅助空间
//设两个结点为p,q
// 情况1:如果p,q在根节点的两侧,那么直接返回根节点(牛逼,没有想到利用根节点两侧结点的共同祖先就是根节点)
// 情况2:如果p,q中有一个为根节点,则直接返回根节点(考虑到p,q在一条链上的情况,很关键)
// 由于从根节点一直向下做上述判断,就一定会进入情况1或情况2,从根节点向下,对每个结点进行上述处理,时间复杂度为O(N)
bool isChildNode(TreeNode* head , TreeNode* node)
{
if(NULL == node)
{
return false;
}
//如果根节点都为空了,说明当前结点不是根节点的子孙结点
if(NULL == head)
{
return false;
}
if(node == head)
{
return true;
}
else
{
//递归处理,注意如果一个结点都不在根节点的左右孩子结点中,那么这个结点必定不是根节点的子孙结点,这里用"||"
return isChildNode(head->left , node) || isChildNode(head->right , node);
}
}
TreeNode* findCommonAncestor(TreeNode* head, TreeNode* node1 , TreeNode* node2)
{
//鲁棒性
if(NULL == head || NULL == node1 || NULL == node2)
{
return NULL;
}
//1如果两个结点中有一个为根节点,直接返回该结点即可
if(node1 == head)
{
return node1;
}
if(node2 == head)
{
return node2;
}
//2如果两个结点分别位于根节点的两侧,则直接返回根节点
bool isNode1OnLeft = isChildNode(head->left , node1);
bool isNode2OnLeft = isChildNode(head->left , node2);
if(isNode1OnLeft != isNode2OnLeft)
{
return head;
}
//3如果两个结点位于根节点同一侧,则令根节点为其同一侧子树的根节点
else
{
//如果都在根节点左侧
if(isNode1OnLeft)
{
return findCommonAncestor(head->left, node1 , node2);
}
else
{
return findCommonAncestor(head->right, node1 , node2);
}
}
}
//解法三:从上往下遍历,最后一个同时包含两个结点的结点即为最低公共结点