236. 二叉树的最近公共祖先(C++)

news2024/11/17 14:20:04

文章目录

  • 前言
  • 一、题目介绍
  • 二、解决方案
  • 三、优化
  • 总结


前言

在本篇文章中我们将会讲解二叉树中极为经典的题目236. 二叉树的最近公共祖先

一、题目介绍

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

示例 1:
在这里插入图片描述

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1
输出:3
解释:节点 5 和节点 1 的最近公共祖先是节点 3 。
示例 2:
在这里插入图片描述

输入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4
输出:5
解释:节点 5 和节点 4 的最近公共祖先是节点 5 。因为根据定义最近公共祖先节点可以为节点本身。

我们举几个例子,方便大家更好的理解
在这里插入图片描述
6和7的公共祖先右5,3,但是题目要求我们找最近公共祖先,也就是5.
在这里插入图片描述
7和5的最近公共祖先是5.

同时注意一下提示:
🌟所有 Node.val 互不相同 。
🌟p != q
🌟p 和 q 均存在于给定的二叉树中。

二、解决方案

我们通过分析可以发现这样的规律

一个节点在左子树,一个节点在右子树,这个节点就是最近公共祖先
一个节点是另一个节点的祖先节点,这个祖先节点就是最近公共祖先

我们可以根据这一特性解决这道问题
🌟判断这个节点是不是根节点,如果是我们就返回这个节点。这时这个节点就是另一个节点的祖先
🌟如果两个节点都在左子树,我们就去左子树寻找
🌟如果两个节点都在右子树,我们就去右子树寻找

class Solution {
public:
    bool IsInTree(TreeNode* root, TreeNode* x)
    {
        if (root == nullptr)
        {
            return false;
        }
        //前序遍历
        if (root == x)
        {
            return true;
        }
        if (IsInTree(root->left, x))
        {
            return true;
        }
        if (IsInTree(root->right, x))
        {
            return true;
        }
        return false;
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
    {
        if (root == nullptr)
        {
            return nullptr;
        }
        //判断这个节点
        if (root == p || root == q)
        {
            return root;
        }

        bool pInLeft, pInRight, qInLeft, qInRight;
        pInLeft = IsInTree(root->left, p);
        pInRight = !pInLeft;
        qInLeft = IsInTree(root->left, q);
        qInRight = !qInLeft;
        //一个在左边,一个在右边,root就是最近公共祖先
        if ((pInRight && qInLeft) || (qInRight && pInLeft))
        {
            return root;
        }
        //都在左边,去左子树找
        if (pInLeft && qInLeft)
        {
            return lowestCommonAncestor(root->left, p, q);
        }
        //都在右边,去右子树找
        else if (qInRight && pInRight)
        {
            return lowestCommonAncestor(root->right, p, q);
        }
        //找不到
        return nullptr;
    }
};

我们看一下时间复杂度:
按照最快情况分析
在这里插入图片描述
1和3的最经公共祖先是13.时间复杂度为O(N*2)

我们能否进行优化呢???

三、优化

我们还有一种解决方案,如果这个节点存了父亲节点,我们就很容易解决这道问题。
转化为:两个链表找交点

但是这道题目没有父亲节点,我们可以转化成求路径
🌟找出两个节点从根节点到这个节点的路径。
🌟路径长的先走差数次
🌟两个路径一起删除节点,最先相同的就是最近公共祖先。

我们通过上帝视角看一下
在这里插入图片描述

找到两条路径
在这里插入图片描述
路径长的先走差数次
在这里插入图片描述
两个路径一起删除节点,最先相同的就是最近公共祖先

在这里插入图片描述

如何查找两条路径??借助栈来实现

进行前序遍历
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码编写

class Solution {
public:
    bool Route(stack<TreeNode*>& s, TreeNode* root, TreeNode* p)
    {
        if (root == nullptr)
        {
            return false;
        }
        //先入栈
        s.push(root);
        //判断这个节点
        if (root == p)
        {
            return true;
        }
        //判断左子树
        if (Route(s, root->left, p))
        {
            return true;
        }
        //判断右子树
        if (Route(s, root->right, p))
        {
            return true;
        }
        //不在左也不再右,从栈里删除这个节点
        s.pop();
        return false;
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q)
    {
        stack<TreeNode*>s1;
        stack<TreeNode*>s2;
        Route(s1, root, p);
        Route(s2, root, q);
        //长的先走
        while (s1.size() != s2.size())
        {
            if (s1.size() > s2.size())
            {
                s1.pop();
            }
            else
            {
                s2.pop();
            }
        }
        //一起走
        while (s1.size())
        {
            //相同
            if (s1.top() == s2.top())
            {
                return s1.top();
            }
            s1.pop();
            s2.pop();
        }
        return nullptr;
    }
};

总结

以上就是今天要讲的内容,本文仅仅详细介绍了236. 二叉树的最近公共祖先(的内容。希望对大家的学习有所帮助,仅供参考 如有错误请大佬指点我会尽快去改正 欢迎大家来评论~~ 😘 😘 😘

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1712400.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BLE蓝牙模块在虚拟车钥匙上的运用—开启无钥匙驾驶新时代

随着科技的不断发展&#xff0c;人们对汽车的智能化需求也日益增长。在这个背景下&#xff0c;BLE蓝牙模块在虚拟车钥匙上的运用应运而生&#xff0c;为消费者带来更加便捷、智能的出行体验。本文将从以下几个方面阐述BLE蓝牙模块在虚拟车钥匙上的应用。   一、什么是BLE蓝牙…

精酿啤酒:品质与口感在啤酒行业竞争中的竞争优势

在啤酒行业中&#xff0c;竞争激烈&#xff0c;品牌众多。要想在竞争中脱颖而出&#xff0c;需要具备与众不同的竞争优势。对于Fendi club啤酒而言&#xff0c;其卓着的品质和与众不同的口感成为了其在竞争中取胜的关键。 品质是啤酒行业竞争中的核心要素。Fendi club啤酒在原料…

Redis中的数据结构与内部编码

本篇文章主要是对 Redis 常见的数据结构进行讲解&#xff0c;同时还对其所对应的不同的内部编码进行讲解。希望本篇文章会对你有所帮助。 文章目录 一、五大数据结构 二、数据结构对应的编码方式 String hash list set zset &#x1f64b;‍♂️ 作者&#xff1a;Ggggggtm &…

node.js(express)+MongoDB快速搭建后端---新手教程

前言&#xff1a; Node.js是一个基于 Chrome V8引擎的JavaScript运行环境&#xff0c;是对于前端工程师来说学习成本最小的后端实现方法&#xff0c;本篇文章总结如何从0-1写一个后端的登录接口 一、检查node环境 先检查自己的node是否安装 一般来说前端工程师的电脑环境肯定…

长安链使用Golang编写智能合约教程(二)

本篇说的是长安链2.3.的版本的智能合约&#xff0c;虽然不知道两者有什么区别&#xff0c;但是编译器区分。 教程三会写一些&#xff0c;其他比较常用SDK方法的解释和使用方法 编写前的注意事项&#xff1a; 1、运行一条带有Doker_GoVM的链 2、建议直接用官方的在线IDE去写合…

【机器学习】Pandas中to_pickle()函数的介绍与机器学习中的应用

【机器学习】Pandas中to_pickle()函数的介绍和机器学习中的应用 &#x1f308; 欢迎莅临我的个人主页&#x1f448;这里是我深耕Python编程、机器学习和自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;并乐于分享知识与经验的小天地&#xff01;&#x1f387; &#…

【Android】【netd】网络相关调试技巧

网络调试技巧总结 ifconfig ifconfig 查看网卡信息 ifconfig -S tcpdump tcpdump -i any -n icmp 查看流量出入ip addr 上面的log 以及ifcong -S 信息可以知道&#xff0c;当前是从wlan0 网卡请求数据。 iptable iptable 部分指令 //禁止www.baidu.com 网址流量进入&a…

网易面试:手撕定时器

概述&#xff1a; 本文使用STL容器-set以及Linux提供的timerfd来实现定时器组件 所谓定时器就是管理大量定时任务&#xff0c;使其能按照超时时间有序地被执行 需求分析&#xff1a; 1.数据结构的选择&#xff1a;存储定时任务 2.驱动方式&#xff1a;如何选择一个任务并执…

在HTML和CSS当中运用显示隐藏

1.显示与隐藏 盒子显示:display:block;盒子隐藏: display:none:隐藏该元素并且该元素所占的空间也不存在了。 visibility:hidden:隐藏该元素但是该元素所占的内存空间还存在&#xff0c;即“隐身效果”。 2.圆角边框 在CSS2中添加圆角&#xff0c;我们不得不使用背景图像&am…

redis面试知识点

Redis知识点 Redis的RDB和AOF机制各是什么&#xff1f;它们有什么区别&#xff1f; 答&#xff1a;Redis提供了RDB和AOF两种数据持久化机制&#xff0c;适用于不同的场景。 RDB是通过在特定的时刻对内存中的完整的数据复制快照进行持久化的。 RDB工作原理&#xff1a; 当执行…

Python 机器学习 基础 之 无监督学习 【聚类(clustering)/k均值聚类/凝聚聚类/DBSCAN】的简单说明

Python 机器学习 基础 之 无监督学习 【聚类&#xff08;clustering&#xff09;/k均值聚类/凝聚聚类/DBSCAN】的简单说明 目录 Python 机器学习 基础 之 无监督学习 【聚类&#xff08;clustering&#xff09;/k均值聚类/凝聚聚类/DBSCAN】的简单说明 一、简单介绍 二、聚类…

Vue3兼容低版本浏览器(ie11,chrome63)

1、插件安装 为了使你的项目兼容 Chrome 63&#xff0c;你需要确保包含适当的 polyfills 和插件配置。你已经在使用 legacy 插件&#xff0c;但在代码中可能缺少一些配置或插件顺序有问题。以下是几个可能的改进&#xff1a; 安装 vitejs/plugin-legacy 插件&#xff1a; 确保…

Midjourney保姆级教程(五):Midjourney图生图

Midjourney生成图片的方式除了使用文字描述生成图片外&#xff0c;还有“图生图”的方式&#xff0c;可以让生成的图片更接近参考的图片。 今天我们来聊聊“图生图”的方式。 一、模仿获取propmt 很多时候&#xff0c;我们不知道画什么内容的图片&#xff0c;大家可以关注内…

一款拥有15000+POC漏洞扫描工具

1 工具介绍 0x01 免责声明 请勿使用本文中所提供的任何技术信息或代码工具进行非法测试和违法行为。若使用者利用本文中技术信息或代码工具对任何计算机系统造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责。本文所提供的技术信息或代码工具仅供于学习&am…

vue3快速上手笔记(尚硅谷)

[TOC]# 1. Vue3简介 2020年9月18日&#xff0c;Vue.js发布版3.0版本&#xff0c;代号&#xff1a;One Piece&#xff08;n 经历了&#xff1a;4800次提交、40个RFC、600次PR、300贡献者 官方发版地址&#xff1a;Release v3.0.0 One Piece vuejs/core 截止2023年10月&#…

经典必读:智能制造数字化工厂建设方案

导语 大家好&#xff0c;我是社长&#xff0c;老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 完整版文件和更多学习资料&#xff0c;请球友到知识星球【智能仓储物流技术研习社】自行下载 战略背景&#xff1a;响应《中国制造2025》及"…

Kibana使用教程

Kibana使您能够轻松地向Elasticsearch发送请求&#xff0c;并以交互方式分析、可视化和管理数据。 1.安装 1.1 docker安装Kibana 如果你还没安装Elasticsearch&#xff0c;先执行docker安装Elasticsearch&#xff0c;下面是单机部署。 创建一个ES网络&#xff1a; docker n…

idea视图中顶部菜单栏找不到VCS

问题描述 idea视图中顶部菜单栏找不到VCS&#xff1a; 解决方案&#xff1a; 直接选择配置过git&#xff0c;此处操作&#xff1a; File->Settings->Version Control-> 点击 ->选择项目->VCS选择none ->点击apply -> 点击ok&#xff1a;

怎样修改库包的文件名?

python中&#xff0c;安装crypto模块时&#xff0c;会遇到crypto文件夹都是小写字母的情况&#xff0c;引用时又是首字母大写&#xff0c;这个时候&#xff0c;需要把库包文件名首字母改为大写字母。windows中一般的文件名命名中字母的大小写是不进行区分的&#xff0c;但是在p…

期权具体怎么交易详细的操作流程?

期权就是股票&#xff0c;唯一区别标的物上证指数&#xff0c;会看大盘吧&#xff0c;交易两个方向认购做多&#xff0c;认沽做空&#xff0c;双向t0交易&#xff0c;期权具体交易流程可以理解选择方向多和空&#xff0c;选开仓的合约&#xff0c;买入开仓和平仓没了&#xff0…