剑指Offer-68:二叉树的最近公共祖先

一、题目描述

在这里插入图片描述

二、解题思路

这是剑指Offer的最后一道题,本质是二叉树的后序遍历(非递归)。牢牢记住二叉树的后序遍历以非递归形式遍历到某一节点时,辅助栈内保存的元素即为根节点到该节点的路径。
知道了上面的性质后,我们就可以利用这两个性质来做题

  • 创建三个栈:遍历栈s,保存pp的路径的栈sp和保存qq的路径的栈sq
  • 遍历到当前节点时,调用拷贝构造函数,把遍历栈s拷贝给spsq
  • 当两个待查找节点全都被遍历到后,马上停止遍历
  • 但是栈内保存的路径是反过来的,最底层栈元素才是根节点,而且路径栈内不保存当前待查节点。而实际上是存在公共祖先为节点本身的这种情况,那么我们就应该知道一定从那个最近公共祖先开始,两个路径到根节点的路径都相同,所以我们将两个栈内保存的路径加上当前节点都转移到vector中去,注意最开始要先加入当前节点,以解决公共祖先为节点本身的这种情况。之后我们反向遍历两个链表,找到最后一个一样的元素即可

三、核心思想

  • 非递归
    • 二叉树的后序遍历以非递归形式遍历到某一节点时,辅助栈内保存的元素即为根节点到该节点的路径
  • 递归
    • root为空,p,q为root时 直接返回root
    • 递归左右,都不为空说明一个在左,一个在右 此时返回root
    • 此时谁不为空返回谁

四、解题代码

非递归

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* pp, TreeNode* qq) {
        if(!root)   return root;
        auto p = root;
        TreeNode* r = nullptr;
        stack<TreeNode*> s, sq, sp;
        unsigned short flag = 0;
        while(p || !s.empty()){
            if(p){
                s.push(p);
                p = p->left;
            }
            else{
                p = s.top();
                if(p->right && p->right != r)
                    p = p->right;
                else{
                    s.pop();
                    if(p == pp){
                        sp = s;
                        flag++;
                    }
                    else if(p == qq){
                        sq = s;
                        flag++;
                    }
                    if(flag == 2)   break;
                    r = p;
                    p = nullptr;
                }
            }
        }
        vector<TreeNode*> vq, vp;
        vq.push_back(qq);
        vp.push_back(pp);
        while(!sq.empty()){
            vq.push_back(sq.top());
            sq.pop();
        }
        while(!sp.empty()){
            vp.push_back(sp.top());
            sp.pop();
        }
        int i, j;
        TreeNode* sln;
        for(i = vp.size() - 1, j = vq.size() - 1; i >= 0 && j >= 0 && vp[i] == vq[j]; i--, j--)	sln = vp[i];
        return sln;
    }
};

递归

class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root || p == root || q == root) return root;
        auto l = lowestCommonAncestor(root->left, p, q);
        auto r = lowestCommonAncestor(root->right, p, q);
        if(l && r)  return root;
        return l ? l : r;
    }
};

五、运行结果

在这里插入图片描述
递归递归
自己写的测试用例
[1,2,3,4,5,6,7,8,9,10,11,12,null,null,null,13,14,15,16,null,17,null,null,18,19,20,21,22,23,null,null,null,null,24,25,null,null,null,null,null,null,null,null]
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44587168/article/details/105743784