236.二叉树的最近公共祖先

  • 二叉树的最近公共祖先
  • 思路1:
    对于两个目标节点p,q的最小公共祖先:① 某个结点,它的左子树中出现了p,q其中一个,右子树出现了另一个,则该节点就是最小公共祖先;② 或p,q两结点中,其中一个是另外一个的祖先,则作为祖先的那个就是最近公共祖先;因此我们下面的逻辑需要覆盖这两种情况;
    想找两个结点的最小公共祖先,肯定是从下往上找,对于二叉树来说就是后序遍历;

我们考虑用递归,由于我们需要知道当前结点到底是不是要找的祖先结点,因此需要返回值bool,但跟题目返回类型是TreeNode不同,还需要重新写一个递归函数,考虑能不能用TreeNode表示我们想要的结果:NULL代表该节点不是目标祖先或目标祖先的祖先(有可能本身该节点是空结点,也有可能是本身非空,但自己下面的子孙并没有找到p或者q,也要返回NULL;注意:当找到目标祖先后,接着往第一层根节点回溯的途中,路径上经过的结点也都会返回非空,才能将结果一层一层返回到根结点处返回),非空就代表以root为根节点的子树中(包含root本身)至少找到了p,q中的一个;

思考时要按一个普通结点去想,把主要逻辑想明白,再去考虑特殊结点是否适合,是否需要加额外判断等等;
现在考虑一个普通的节点root,若root本身就是p,q其中一个就直接返回root,代表以root为根结点的子树最终找到了一个目标结点。当然root为空也直接返回,就像正常的后序遍历一样,也可以理解为以root为根节点的子树最后没找到目标结点;若root自己不是目标结点且非空,那么就要想办法去看看它的子孙后代里面是否有,那么就对root->left和root->right分别递归调用,并保存返回值l和r;最后root到底是不是我们要找的最近公共祖先,就需要看l和r的结果了;这道题的递归虽然有返回值,但实际也要遍历整棵树,毕竟函数最初的入口是第一层根节点root,即使我们从下往上找到了那个公共祖先结点,也要一层一层返回上来,最后由第一层递归返回最终结果

//后序遍历
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    	//若root本身就是p,q其中一个,就直接返回root。
    	//情况:假如p是q的祖先,因此题目已经说了p,q一定都在树里,那么既然p,q都在一侧,那树的另外一半肯定就找不到,一层一层回溯到第一层根节点
    	//时,自然是左右子树一半返回p,q中作为祖先的那个,另一半返回NULL,则最终停在下面的某个else if分支。即定义里面的情况②;
    	//情况①也一样,假如p在左q在右,在找到p之后,p下面的结点同样不会被访问到,只是由于此时q确实是在右子树,因此最终停止的位置是下面的else分支
        if (root == p || root == q || root == NULL) return root;
		
		//若root本身不是p,q,则判断root有没有可能满足定义的情况①?
        TreeNode* l = lowestCommonAncestor(root->left, p, q);//左
        TreeNode* r = lowestCommonAncestor(root->right, p, q);//右

        //中
        if(l == NULL && r == NULL) return NULL;
        else if(l == NULL) return r;
        else if(r == NULL) return l;
        else return root;
};
  • 递归实际隐藏的细节太多,写之前很难把所有case都想到
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值