题目:
输入两个树节点,求它们的最低公共祖先。
分析:
这道题对于不同的树有不同的解法,分为以下几类:
1.二叉搜索树。
2.普通树,但结点中有指向父节点的指针。
3.普通数。
1.二叉搜索树
二叉搜索树中结点的左孩子值都小于结点的值,结点的右孩子值都大于结点的值。两个树结点的最低公共祖先肯定是将这两个树结点分隔到了不同的两个子树中,所以最低公共祖先的值肯定介于这两个树结点之间。从上往下遍历二叉搜索树,如果当前结点的值大于这两个树结点的值,就在当前结点的左子树中找,如果当前结点的值小于这两个树结点的值,就在当前结点结点的右子树中找,找到第一个值介于给定的两个树结点的值的结点就是这两个树结点的最低公共祖先。
参考代码:
struct TreeNode
{
int value;
TreeNode* left;
TreeNode* right;
};
class Solution
{
public:
TreeNode* getClosestCommonAncestor( TreeNode* node1, TreeNode* node2, TreeNode* root )
{
if ( node1 == NULL || node2 == NULL )
return NULL;
while ( root != NULL )
{
if ( root->value > node1->value && root->value > node2->value )
{
root = root->left;
}
else if ( root->value < node1->value && root->value < node2->value )
{
root = root->right;
}
else
{
return root;
}
}
return root;
}
};
2.普通树,但结点中有指向父结点的指针
如果树中有指向父结点的指针,就可以从给定的两个结点开始往回追溯,找到回溯路径中第一个公共结点。这个问题就可以转化为求两个链表的第一个公共结点。
参考代码:
struct TreeNode
{
int value;
TreeNode* left;
TreeNode* right;
TreeNode* parent;
};
class Solution
{
public:
TreeNode* getClosestCommonAncestor2( TreeNode* node1, TreeNode* node2, TreeNode* root )
{
if ( node1 == NULL || node2 == NULL || root == NULL )
return NULL;
int node1Length = 0, node2Length = 0;
int diffLength = 0;
TreeNode* node1Temp = node1;
TreeNode* node2Temp = node2;
//分别计算两个结点到根结点的路径的长度
while ( node1Temp != NULL )
{
node1Temp = node1Temp->parent;
node1Length++;
}
while ( node2Temp != NULL )
{
node2Temp = node2Temp->parent;
node2Length++;
}
node1Temp = node1;
node2Temp = node2;
//让路径较长的结点先走
if ( node1Length >= node2Length )
{
diffLength = node1Length - node2length;
while ( diffLength != 0 )
{
node1Temp = node1Temp->parent;
}
}
else if ( node2Length < node2Length )
{
diffLength = node2Length - node1Length;
while ( diffLength != 0 )
{
node2Temp = node2Temp->parent;
}
}
//同步前进,找到第一个公共结点
while ( node1Temp != NULL && node2Temp != NULL )
{
if ( node1Temp == node2Temp )
{
break;
}
else
{
node1Temp = node1Temp->parent;
node2Temp = node2Temp->parent;
}
}
return node1Temp;
}
};
3.普通树
利用辅助栈,在遍历树的时候找到根结点到两给定结点的路径,然后将其转化为两个链表求公共结点问题。
参考代码:
struct TreeNode
{
int value;
TreeNode *left;
TreeNode *right;
};
class Solution
{
public:
TreeNode* getClosestCommonAncestor3( TreeNode* node1, TreeNode* node2, TreeNode* root )
{
if ( node1 == NULL || node2 == NULL || root == NULL )
return NULL;
stack<TreeNode*> path1;
stack<TreeNode*> path2;
getNodePath( root, node1, path1 );
getNodePath( root, node2, path2 );
return getCommonNodeFromStack( path1, path2 );
}
TreeNode* getCommonNodeFromStack(
const stack<TreeNode*>& path1,
const stack<TreeNode*>& path2 )
{
int diffLength = 0;
if ( path1.size() > path2.size() )
{
diffLength = path1.size() - path2.size();
while ( diffLength != 0 )
{
path1.pop();
diffLength--;
}
}
else
{
diffLength = path2.size() - path1.size();
while ( diffLength != 0 )
{
path2.pop();
diffLength--;
}
}
while ( !path1.empty() && !path2.empty() )
{
if ( path1.top() == path2.top() )
{
break;
}
path1.pop();
path2.pop();
}
return path1.top();
}
bool getNodePath( TreeNode* root, TreeNode* findNode, stack<TreeNode*>& path )
{
if ( root == NULL )
return false;
if ( root == findNode)
{
path.push( findNode );
return true;
}
if ( getNodePath( root->left, findNode, path )
|| getNodePath( root->right, findNode, path ) )
{
path.push( root );
}
}
};