这个问题是剑指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; }