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

祖先节点

祖先节点指从根开始到该节点路径上的所有节点

思路

拿到这道题先分析树是什么树,是搜索树还是普通的二叉树。

搜索树

由搜索树性质可得,如果根的左子树所有节点比根小,根的右子树所有节点比根大。
那么分一下几种情况:
1 某一个节点为根节点,那么公共节点就是根节点了。
2 这俩个节点在不同子树,那么公共节点就是根节点。
3 这俩个节点在同一子树。
所以根据以上分析,可得我们可以通过不断的递归直到找到一个子树,在该子树中俩节点分别位于它的左子树和右子树,那么该子树节点就是公共节点。

代码
Node* findCom_ancestor(Node*Root, Node*x, Node*x2)
{
    if (Root == NULL) return NULL;
    if (x == Root || x2 == Root) return Root;
    if (x->_data > Root->_data&&x2->_data < Root->_data)
    {
        return Root;
    }
    if (x->_data<Root->_data&&x2->_data>Root->_data)
    {
        return Root;
    }
    if (x->_data < Root->_data)
    {
        return findCom_ancestor(Root->_PLeft, x, x2);
    }
    else{
        return findCom_ancestor(Root->_PRight, x, x2);                                                                                                                                                              
    }
}
普通二叉树

思路
方法1
以上面的思路为参考,只要不断的判断俩节点是否位于不同子树即可,找到位于不同子树的根节点即可。
所以每次都要判断一次是否在该子树中。所以时间复杂度较高为 N2。
方法2
自己写个关于路径的函数,保存路径上的所有节点到栈中,通过栈的特性后进先出,所以从该节点从上一直遍历栈中保存的节点信息,是否有相同的,第一个相同的即为最近公共祖先节点。

方法2代码
bool path(stack<Node*>& s, Node*Root, Node*x)
{
    if (Root)
    {
        if (Root == x)
        {                                 
            return true;                //这里找到不用在push了,因为是先入栈再查找的
        }
        s.push(Root->_PLeft);                   //先入栈假设在左子树
        if (path(s, Root->_PLeft, x))           //进左子树查找
            return true;
        else
             s.pop();                               //走到这里这里说明左子树没有,所以把之前入栈的左子树节点pop出来
        s.push(Root->_PRight);                      //再继续假设在右子树
        if (path(s, Root->_PRight, x))                //查找
            return true;
        else 
            s.pop();                             //不在右子树把之前的节点出栈
    }
    return false;
}
Node* findCom_ancestor(Node*Root, Node*x, Node*x2)
{
    if (Root == NULL || x == NULL || x2 == NULL)
    {
        return NULL;
    }
    if (Root==x||Root==x2)
    {
        return Root;
    }
    /*path处理,先保存路径所有节点*/
    stack<Node*> scon1;
    stack<Node*> scon2;
    scon1.push(Root);//这里我先把Root入栈是因为我写的Path函数里没有把Root入栈,只是把路径上的所有子节点放入栈中
    scon2.push(Root);
    if (!path(scon1, Root, x)) return NULL; //如果没找到,说明该节点不在此子树中所以return NULL
    if (!path(scon2, Root, x2)) return NULL;
    int gap = 0;//走到这 scon肯定不为空
    int  size = scon1.size();
    int size2 = scon2.size();
    gap = (size > size2) ? size - size2 : size2 - size;
    if (size > size2)
    {
        while (gap-- != 0)
        {
            scon1.pop();
        }
    }
    if (size2 > size)
    {
        while (gap-- != 0)
        {
            scon2.pop();
        }
    }
    /*这里处理栈中数据看找到最近祖先节点*/
    Node*pCur = scon1.top();
    Node*pCur_2 = scon2.top();
    while (pCur != pCur_2) //先比较再pop
    {
        scon1.pop();
        scon2.pop();
        if (scon1.empty()||scon2.empty()) break;
        pCur = scon1.top(); //即使这里俩个都取到最后一个节点也没问题,因为是先比较的
        pCur_2 = scon2.top();
    }
    if (pCur == pCur_2) return pCur;
    return NULL;  
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值