【面试题之算法部分】LCA最近公共祖先

问题描述:给定一棵二叉树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;
}
    原文作者:YoungLeoo
    原文地址: https://blog.csdn.net/YoungLeoo/article/details/47953069
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞