最近公共祖先问题

 递归法:

树就是递归的描述, 每一次递归都是一个子树,可以简化为root, left, right

思路:对于任意一个节点,把其当作root,分别在他的左子树和右子树中查询,

情况一: 他的左子树中能够找到p和q,右子树不能找到p和q, 则说明当前的递归层的root是公共祖先,一定不是最近公共祖先,其left可能是最近公共祖先

情况二:他的右子树中能够找到p和q,左子树中不找到p和q, 则说明当前的递归层的root是公共祖先,一定不是最近公共祖先,其right可能是最近公共祖先

情况三:他的左子树和右子树分别能找到p或者q,则该递归层的root一定是最近公共祖先

理解到这里,可能脑子仍然只是有一个概念,仍然无法细致理解,不急,慢慢说来

我们理解一下:如果判断left或者right是不是最近的公共祖先。首先递归可以分为 递进和回溯 两个过程

递进的过程:

1.树的入口root节点无论是从左子树还是右子树最后会有可能递进到叶子节点,叶子节点的left和right是NULL,从叶子节点递进,那么此时的root为NULL,所以该结束递进过程了,即一个终止条件就是root==NULL

2.root节点从左子树或者右子树最后可能会找到p或者q,如果找到了他们,则没有必要继续递进下去了,所以另外一个结束条件是root==p或者root==q

从递进的过程中可以找到递归结束的条件

回溯过程:

回溯过程会发生在递进过程达到终止条件时,所以从终止条件开始理解回溯过程。 每一次递进层都应该返回 一个值给上一个递进层,要么NULL,要么是p,要么q,这个返回值的意义是:上一个递归层的left或者right有没有找到p或者q

假设递进层的root为叶子节点,那么当前递进层left和right都会为NULL,说明了当前递层的root,left,right都是p或者q,返回NULL, 而当前叶子节点递归层可能是上一个递归层(叶子节点的父节点)的left或者right,所以其left或者right就会为NULL,

如果上层递归的left和right都为NULL,那么上上层的left或者right就会为NULL,依次类推。但是如果left是NULL, right不是NULL,则当前递归层应该返回right,表面上个递归层的left或者right找到了p或者q;如果回溯到某一个递归层的left和right都不为NULL,则说明该递归层的root就为最近公共祖先了。为什么是最近的呢?注意这是回溯过程,是从p或者q开始回溯,找到的第一个公共祖先当然是最近的,找到之后这个最近公共祖先后,每次返回给上一个递归层的left,right都有这个最近公共祖先。

如何理解这句话: 假设这个最近公共祖先返回给了上一次递归层R_1的rihgt,那么R_1的left一定为NULL, 同理上上 一次的递归层R_0的left和right也一定会有一个NULL,所以返回也是这个最近公共祖先。这是由二叉树的性质决定的,即最近公共祖先位于左子树,则右子树一定为NULL。

可以结合下面的代码理解:Solution记录了整个递归过程root,left和right的值。 Solution2是Solution的分解版

#include <iostream>
using namespace std;
struct TreeNode
{
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x): val(x), left(NULL), right(NULL){}
};

class Solution{
    public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){
        if (root != NULL){
         cout << "root:"<< root->val << endl;
        }else{
            cout << "root:" << "NULL" << endl;
        }
        if(root == NULL || p == root || q == root ){
            return root;
        }

        TreeNode* fleft = lowestCommonAncestor(root->left, p, q);
        if (fleft != NULL){
             cout << "left:" << fleft->val << endl;
        }
        else{
            cout << "left:" << "NULL" << endl;
        }
        TreeNode* fright = lowestCommonAncestor(root->right, p, q);
        if (fright != NULL){
            cout << "right:" << fright->val << endl;
        }
        else{
            cout << "right:" << "NULL" << endl;
        }
        if (!fleft){
            return fright;
        }

        if (!fright){
            return fleft;
        }

        return root;
    }
};

class Solution2{
    public: 
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q){
        if (root == p || root == q){
            return root;
        }
        TreeNode* tleft = findAncester(root->left, p, q);
        TreeNode* tright = findAncester(root->right, p, q);

        if (tleft == NULL){
            return tright;
        }
        if (tright == NULL){
            return tleft;
        }
        if (tleft != NULL && tright != NULL){
            return root;
        }

        if (tleft == NULL && tright == NULL){
            return root;
        }

    }

    TreeNode*  findAncester(TreeNode* root, TreeNode* p, TreeNode* q){

            if (root == NULL){
                return root;
            }
            if (root->val == p->val || root->val == q->val){
                return root;
            }
            TreeNode* tleft = findAncester(root->left, p, q);
            TreeNode* tright = findAncester(root->right, p, q);
            if (tleft == NULL)
            {
                return tright;
            }
            if (tright == NULL)
            {
                return tleft;
            }
            if (tleft != NULL && tright != NULL)
            {
                return root;
            }
            
    }
};


TreeNode* root = new TreeNode(1);
TreeNode* l = new TreeNode(3);
TreeNode* r = new TreeNode(7);
TreeNode* ll = new TreeNode(4);
TreeNode* lr = new TreeNode(11);
TreeNode* rl = new TreeNode(12);
TreeNode* rr = new TreeNode(5);
TreeNode* lll = new TreeNode(6);
TreeNode* llr = new TreeNode(8);

int main(){
root->left = l;
root->right = r;
root->left->left = ll;
root->right->left = rl;
root->right->right = rr;     
root->left->left->left = lll;
root->left->left->right = llr;
Solution2 *s = new Solution2();
cout << rl->val << "," << rr->val << endl;
TreeNode* findroot = s->lowestCommonAncestor(root, rl, rr);
cout<< findroot->val<<endl;
return 0;
}

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值