二叉树中两个节点的最低公共祖先

这个问题是剑指OFFER最后一个面试的例子,看了以后有一些自己的想法,记录下来,希望能和大家分享自己的思路。


1、如果这棵树是一颗二叉查找树

首先需要判断两个节点是否在树中,且树不能为空。然后从根节点开始,若根节点的值同时>或<两个节点的值,那么说明这两个节点同时在根节点的左子树或右子树上,此节点不是要寻找的最低公共祖先。然后递归寻找树的左子树和右子树,直到找到结果。

TreeNode* GetLastCommonNode( TreeNode* Head, TreeNode* p1, TreeNode* p2)
{
	if( !exist(p1) || !exist(p2) || !Head) return NULL;     // 两节点是否存在
	
	while( Head!=NULL) {
        
		// 两节点分别在Head左右子树上
        if( (Head->key - p1->key)*(Head->key - p2->key)<=0) return Head; 
		
		if( Head->key > p1->key) Head = Head->right;    // 两节点同时在Head右子树上
		else Head = Head->left;                         // 两节点同时在Head左子树上
	}

	return NULL;
}

2、如果这棵树带有指向父节点的指针

由于带有指向父节点的指针,且每个节点都有唯一的父节点(根节点除外),那么可以从下向上访问两个节点的父节点,直到到达根节点,将路径倒置存入到两个链表中,然后判断两个链表中最后一个公共元素,即最低公共祖先。

TreeNode* GetLastCommonNode( TreeNode* Head, TreeNode* p1, TreeNode* p2)
{
	list<TreeNode*> l1, l2;
	
	while( p1!=NULL) {
		l1.push_front(p1);            // 倒序放入父节点信息
		p1 = p1->p;
	}
	while( p2!=NULL) {
		l2.push_front(p2);
		p2 = p2->p;
	}
	
	TreeNode* temp;                   // 两个链表中最后一个公共元素
	list<TreeNode*>::iterator i, j;   // 两个迭代器
	
	for ( i=l1.begin(),j=l2.begin(); i!=l1.end() && j!=l2.end(); i++, j++) {
		if( i==j) temp = i;
	}
	
	return temp;
}


3、如果这棵树是颗普通的二叉树

这是剑指OFFER中面试官最后问的一个问题,在面试官的引导下,面试者给出了最后答案,分别从根节点开始查找两个节点,将到达两个节点的路径存入链表,然后判断这两个链表中最后一个公共元素,即其最低公共祖先。

上述这种方法需要遍历两次树得到两个链表,然后进行求解。下面通过使用栈对上述方法进行优化实现一次遍历得到结果。在深度优先的遍历规则下就是使用栈来存储节点信息,当我们遍历到一个节点p1时,实际上栈中存储的就是从根节点到p1的一条路径。当我们继续遍历第二个节点p2时,就会发现实际上两者的所有公共父节点并没有出栈,出栈、进栈的只是两者之间的非公共节点。那么,我们可以在栈中多存储一个flag信息,遍历第一个节点进栈的元素flag为1,再遍历第二个节点进栈的元素flag为0。最后我们依次取出栈中元素,第一个flag为1的节点就是我们所找的最低公共祖先。

见下图:


typedef pair<TreeNode*,int> Node;
int flag;                       // flag+1表示未查找到的节点数

// 查询两个节点, 并将路径记录到栈中
void FindNode(  TreeNode* Head, TreeNode* p1, TreeNode* p2, stack<Node> &s)
{
	if( flag==-1 || Head==NULL) return;
	
	Node n( Head, flag);
	node.push( n);              // 放入要查找的节点
	
	if( Head==p1 || Head==p2) flag--;
	FindNode(  Head->left , p1, p2, &s);
	FindNode(  Head->right, p1, p2, &s);
	
	if( flag!=-1) node.pop();   // 非最终路径上的节点, 删除节点
}

TreeNode* GetLastCommonNode( TreeNode* Head, TreeNode* p1, TreeNode* p2)
{
	stack<Node> s; flag = 1;    // flag置1
	FindNode(  Head, p1, p2, &s);
	
	while( !s.empty()) {        // 返回第一个flag为1的 TreeNode
		if(s.top().second==1) return s.top().first;
		s.pop();
	}
	
	return NULL;
}

猜你喜欢

转载自blog.csdn.net/zhanw15/article/details/80441319