树中两个节点的最低公共祖先

一.树中两个节点的最低公共祖先

题目一: 输入两个二叉搜索树的结点,求两个结点的最低公共祖先,所谓的最低公共祖先是指距离两个节点最近的共同祖先。

例如:
这里写图片描述

解题思路:

  • 1.二叉搜索树具有一个很好的特点。以当前结点为根节点的左边结点的值都是小于根节点的值,右边结点的值都大于根节点的值。
  • 2.根据这个特点,如果给的两个节点的值都小于根节点,那么它们的最低公共祖先就一定在它左子树。
  • 3.如果给的两个节点的值都大于根节点,那么它们的最低公共祖先就一定在它右子树。
  • 4.如果一个结点的值大于根节点的值一个结点的值小于根节点的值,那么这个根节点就是它的最低公共祖先。
    代码实现:
//求两个节点的最低公共祖先(递归解法)
BSTreeNode* GetCommenParent_R(BSTreeNode* root, BSTreeNode* bstn1, BSTreeNode* bstn2)
{
	if (root == NULL || bstn1 == NULL || bstn2 == NULL)
		return NULL;

	if ((bstn1->_data < root->_data) && (bstn2->_data< root->_data))
	{
		GetCommenParent_R(root->_left, bstn1, bstn2);
	}
	else if ((bstn1->_data>root->_data) && (bstn2->_data>root->_data))
	{
		GetCommenParent_R(root->_right, bstn1, bstn2);
	}
	else
		return root;
}

题目二: 假设在修改一下上述题目的条件,所给的树不是一棵二叉搜索树,甚至不是一棵二叉树,只是一棵简单的树,但是树中的结点存在着指向父节点的指针,那么要怎么求出两个结点的最低公共祖先呢?
这里写图片描述

解决思路:转换题目。

  • 1.假设在上边的树中,题目给出3和78两个结点
  • 2.我们可以发现从树的叶节点到根节点有唯一的一条路径,也就是一条链表
  • 3.3->12->32,78->45->32
  • 4.要求它们的最低公共祖先,就是转换成求上述两条链表的第一个公共结点

求两条链表的第一个公共结点位于我的另一篇博客:
https://blog.csdn.net/hansionz/article/details/82717368

题目三:假设在次修改题目二的条件,这只是一棵普通的二叉树,并没有指向父亲的指针,我们该怎样做呢?

解题思路一:

  • 如果一个结点为根,另一个结点无论在什么地方它们的最低公共祖先一定为根结点。

  • 如果一个结点在左树,另一个结点在右树,那么它的最低公共祖先一定是根节点。

  • 如果两个结点都在左树,以子问题在左树查找。

  • 如果两个结点都在右树,以子问题在右树查找。

代码实现:

//找一个结点
struct TreeNode* GetNode(struct TreeNode* root, struct TreeNode* cur){
    if(root==NULL){
        return NULL;
    }
    if(root->val==cur->val){
        return root;
    }
    
    struct TreeNode* ret=GetNode(root->left,cur);
    if(ret){
        return ret;
    }
    return GetNode(root->right,cur);
}
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
    if(root->val==p->val||root->val==q->val){
        return root;
    }
    bool pleft,pright,qleft,qright;
    
    if(GetNode(root->left,p)){
        pleft=true;
        pright=false;
    }
    else{
        pleft=false;
        pright=true;
    }
    if(GetNode(root->left,q)){
        qleft=true;
        qright=false;
    }
    else{
        qleft=false;
        qright=true;
    }
    //一个在左,一个在右,返回根
    if((pleft&&qright)||(pright&&qleft)){
        return root;
    }
    //两个都在左
    if(pleft&&qleft){
        return lowestCommonAncestor(root->left,p,q);
    }
    //两个都在右
    if(pright&&qright){
        return lowestCommonAncestor(root->right,p,q);
    }
    
    return NULL;
}

解决思路二: 用辅助栈解决。
在这里插入图片描述

代码实现:

//将结点的路劲放到辅助栈中
int GetNodePath(struct TreeNode* root, struct TreeNode* cur,Stack* s){
    if(root==NULL){
        return 0;
    }
    StackPush(s,root);
    if(root->val==cur->val){
        return 1;
    }
    if(GetNodePath(root->left,cur,s)==1){
        return 1;
    }
    if(GetNodePath(root->right,cur,s)==1){
        return 1;
    }
    //走到这说明左右都没有,回溯
    StackPop(s);
    return 0;
}
struct TreeNode* lowestCommonAncestor(struct TreeNode* root, struct TreeNode* p, struct TreeNode* q) {
    if(root->val==p->val||root->val==q->val){
        return root;
    }
    Stack pPath;
    Stack qPath;
    StackInit(&pPath);
    StackInit(&qPath);
    GetNodePath(root,p,&pPath);
    GetNodePath(root,q,&qPath);
    
    while(StackSize(&pPath)!=StackSize(&qPath)){
    	//大的先出栈
        if(StackSize(&pPath)>StackSize(&qPath)){
            StackPop(&pPath);
        }
        else{
            StackPop(&qPath);
        }
    }
    while(StackTop(&pPath)!=StackTop(&qPath)){
        StackPop(&pPath);
        StackPop(&qPath);
    }
    if(StackSize(&pPath)>0){
        return StackTop(&pPath);
    }
    return NULL;
}

注:关于栈的一些基础操作位于我的另一篇博客:https://blog.csdn.net/hansionz/article/details/81636557

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值