当前位置: 首页 > article >正文

<刷题笔记> 力扣236题——二叉树的公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

                                           

题目解释:

我们以这棵树为例,来观察找不同的最近公共祖先有何特点:

思路一: 

除了第二种情况,最近公共祖先满足:一个节点在他的左边,一个节点在他的右边。

并且,其他公共祖先不满足这个条件,只有最近公共祖先满足这一点。 

所以我们可以利用这个逻辑来破题:从根节点开始往下查找,找到的第一个满足“p和q分别在他的左右两侧的节点”,就是要找的最近公共祖先。

先来特殊处理第二种情况:

然后涉及到最关键的步骤:

分别用bool值封装q和p找位置的函数,便于依次罗列出q和p对于当前节点的位置(是否满足一左一右)

实现IsInTree:

完整代码:

bool IsInTree(TreeNode* tree,TreeNode* k){
        if(tree==nullptr) return false;
        return tree==k
            || IsInTree(tree->left,k)
            || IsInTree(tree->right,k);
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
       //特殊处理本身存在爷孙或父子关系的情况
        if(root == p || root == q){
            return root;
        }
        //罗列出p和q是否存在的条件
        bool PInLeft = IsInTree(root->left,p);
        bool PInRight = !PInLeft;
        bool QInLeft = IsInTree(root->left,q);
        bool QInRight = !QInLeft;
        //分类讨论
        if((PInLeft && QInRight) || (QInLeft && PInRight)){
            return root;
        }else if(PInLeft && QInLeft){
            return lowestCommonAncestor(root->left,p,q);
        }else{
            return lowestCommonAncestor(root->right,p,q);
        }
        //return nullptr;
    }
};

但是实际运行速度并不理想: 运行速度几乎都要接近一秒了

这样操作的时间复杂度是O(N^2):

因为我们的树是一个毫无数据存放逻辑的任意形状的二叉树。所以,每一次去判断IsInTree都是把当前root下面的数据都遍历一遍,因此其本质其实是:第一遍从3开始查左查右,第二次从5开始查左查右,再从6开始查左查右......

如果遇到最坏的如下图一样的环境:

其时间复杂度是O(N^2)

当然,如果越接近完全二叉树的情形,时间复杂度越低,最理想能达到O(n)

                                       


思路二:

如果我们能根据找祖先的两个节点往回走,一切都会很好解决。

这样就变成了两条相交链表找交点。

使用前序查找+栈来找记录路径,然后再进行一次“两条相交链表找交点”

                                                

比如这张图,要找7,那么我们的路径应该记录为:3-5-2-7

在遇到6这样的错误的分支方向时,我们先将其入栈,发现他不对就出栈。

class Solution {
public:
    bool FindPath( stack<TreeNode*>& st , TreeNode* des , TreeNode* root){
        if(root==nullptr) {
            return false;
        }
        st.push(root);
        if(root == des){
            return true;
        }else if((!FindPath(st,des,root->left))&&
                 (!FindPath(st,des,root->right))){
                  st.pop();
                  return false;
                }
            return true;
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack<TreeNode*> q_path;
        stack<TreeNode*> p_path;
        FindPath(q_path,q,root);
        FindPath(p_path,p,root);

        while(q_path.size()!=p_path.size()){
            if(q_path.size()>p_path.size()) q_path.pop();
            if(p_path.size()>q_path.size()) p_path.pop();
        }

        while(q_path.top()!=p_path.top()){
            q_path.pop();
            p_path.pop();
        }

        return q_path.top();
    }
};

可以发现现在这种方法提升了不少速度: 

欢迎各位看官在评论区写出对这道题的其他解法。


http://www.kler.cn/a/314997.html

相关文章:

  • linux上海康SDK安装并设置环境变量
  • ctfshow-web入门-SSTI(web361-web368)上
  • ima.copilot-腾讯智能工作台
  • 如何为电子课程创造创意
  • pycharm快速更换虚拟环境
  • Python如何从HTML提取img标签下的src属性
  • 全面详尽的 PHP 环境搭建教程
  • C++ 元编程
  • 18938 汉诺塔问题
  • 《深度学习》PyTorch 常用损失函数原理、用法解析
  • 【电力系统】基于遗传算法的33节点电力系统无功优化及MATLAB实现
  • LeetCode337. 打家劫舍III
  • springbootKPL比赛网上售票系统
  • Maven 项目无法下载某个依赖
  • 论 JAVA 集合框架中 接口与类的关系
  • 注册信息安全专业人员(CISP)和网络安全的联系与区别
  • FLStudio21Mac版flstudio v21.2.1.3430简体中文版下载(含Win/Mac)
  • windows cuda12.1 pytorch gpu环境配置
  • js之遍历方法
  • windows@文件系统链接@快捷方式@快捷键方式和符号链接及其对比
  • 本地提权【笔记总结】
  • 《AI:开启未来的无限可能》
  • 【django】局域网访问django启动的项目
  • MongoDB解说
  • 机器人速度雅可比矩阵(机器人动力学)
  • 自动化立体仓库与堆垛机单元的技术参数