算法:寻找树中两个结点的最低公共祖先

题型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);  
		}  
	}  
}  

//解法三:从上往下遍历,最后一个同时包含两个结点的结点即为最低公共结点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值