问题描述:给定一棵二叉树T和两个节点u和v,找出u和v离根节点最近的公共祖先。
首先我们将这个问题分成三种情况:
情况一: 二叉树是二叉查找树。
这种情况比较简单,将当前节点初始化为根节点,从当前节点开始,不断将当前节点的值和u节点的值、v节点的值作比较,如果当前节点值同时小于二者,则将当前节点的右孩子作为当前节点,继续比较;如果当前节点值同时大于二者,则将当前节点的左孩子作为当前节点,继续比较;如果当前节点的值在二者之间,说明当前节点即为u和v的最近公共祖先。
代码如下:
bstNode *LCA(bstNode *pNode, int value1, int value2)
{
bstNode *pTemp = pNode;
while(pTemp)
{
if(pTemp->data > value1 && pTemp->data > value2)
pTemp = pTemp->lChild;
else if(pTemp->data < value1 && pTemp->data < value2)
pTemp = pTemp->rChild;
else return pTemp;
}
return NULL;
}
情况二:二叉树为普通二叉树,根节点未知,但是每个节点都有parent指针。
分析:首先最容易想到的是暴力法。从u节点开始向上遍历,每遍历一个节点,就从v节点开始遍历到根节点,将每个值拿出来与v节点的值相比较,如果两个节点的值相同,则说明该节点就是最近公共祖先,从该节点往上的链表都是重合的,假设从u开始到跟根节点的长度为m,从v节点到根节点的长度为m,则平均时间复杂度为O(mn)。有没有优化的算法呢,进一步分析,我们假设m>=n,由于从两个链表的第一个公共节点开始一直到链表的尾(即根节点)是完全重合的,所以前m-n个节点一定没有公共节点,我们从长的链表上遍历m-n次后,再同步遍历两个链表,依次比较两个节点的值,直到找到相同的节点,该节点即为最近公共祖先。时间复杂度为O(m+n)
情况三:普通二叉树,没有parent指针,只有left/right指针。
我们采用递归的方式来需找最近公共祖先。
代码如下:
node *getLCA(node *root, node *node1, node *node2)
{
if(root == NULL) return NULL;
if(root == node1 || root == node2) return root;
node *left = getLCA(root->left, node1, node2);
node *right = getLCA(root->right, node1, node2);
if(left != NULL && right != NULL) return root;
else if(left != NULL) return left;
else if(right != NULL) return right;
else return NULL;
}