LeetCode 热题 100_二叉树的最近公共祖先(49_236_中等_C++)(二叉树;深度优先搜索)
LeetCode 热题 100_二叉树的最近公共祖先(49_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 。因为根据定义最近公共祖先节点可以为节点本身。
示例 3:
输入:root = [1,2], p = 1, q = 2
输出:1
提示:
树中节点数目在范围 [2, 105] 内。
-109 <= Node.val <= 109
所有 Node.val 互不相同 。
p != q
p 和 q 均存在于给定的二叉树中。
题解:
解题思路:
思路一(深度优先搜索):
1、在解决此问题时我们首先应该讨论一下p,q在二叉树中的各个分布情况。假设一个结点为root为当前遍历的结点。
递归出口:
① root结点为null则返回(递归出口)(返回null)
② 当前结点为p,返回p(第一次发现p,且未找到q)(返回当前结点,因当前结点可能为祖先)
(为什么直接返回呢,因为我们可以通过遍历除p的子孙节点外的其他结点来判断q的位置:若其他结点中存在q,则p不是q的祖先。若其他结点不存在q,则q是p的子孙,p为公共祖先结点)
③ 当前结点为q,返回q(第一次发现q,且未找到p)(返回当前结点,因当前结点可能为祖先)
(为什么直接返回呢,因为我们可以通过遍历除q的子孙节点外的其他结点来判断p的位置:若其他结点存在p则,q不是p的祖先。若其他结点不存在p,则p是q的子孙,q为公共祖先结点)
递归体: 按深度优先遍历递归的寻找左右子树。
判断当前节点的左右子树(左右子树遍历完后):
① 当前结点左右子树都没有查找到p或q。(返回null)
② 当前结点左子树找到一个结点(p或q),右子树找到一个结点(p或q)。(返回当前结点,当前结点为公共祖先)
③当前结点左子树找到一个结点(p或q),右子树没找到。(返回左子树找到的结点)
④ 当前结点右子树找到一个结点(p或q),左子树没找到。(返回右子树找到的结点)
2、复杂度分析:
① 时间复杂度:O(n),n代表二叉树中结点的个数,最坏的情况会遍历整颗二叉树。
② 空间复杂度:O(n),采用的是深度遍历搜索,所以需要用到函数栈,最坏情况下为O(n)。
代码实现
代码实现(思路一(深度优先搜索)):
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//遍历到nullptr或者p、 q则返回if (root==nullptr||root==p||root==q) return root;//递归的进行查找TreeNode *left=lowestCommonAncestor(root->left,p,q);TreeNode *right=lowestCommonAncestor(root->right,p,q);//如果当前结点的左右子树都没查找到q或p,则返回nullptrif(left==nullptr&&right==nullptr) return nullptr;//查找到p、q的公共祖先则返回该结点if (left!=nullptr&&right!=nullptr) return root;//p或q存在左子树则返回左子树对应的结点if (left!=nullptr) return left;//p或q存在右子树则返回右子树对应的结点return right;
}
以思路一为例进行调试
#include<iostream>
#include <vector>
#include <queue>
using namespace std;struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};//通过数组创建二叉树,-1代表nullptr;
TreeNode *createTree(vector<int> nums){if (nums.empty()){return nullptr;}queue<TreeNode *> q;TreeNode *root=new TreeNode(nums[0]);q.push(root);int i=1;while (i<nums.size()){TreeNode *node=q.front();q.pop();if (i<nums.size()&&nums[i]!=-1){node->left=new TreeNode(nums[i]);q.push(node->left);}++i;if (i<nums.size()&&nums[i]!=-1){node->right=new TreeNode(nums[i]);q.push(node->right);}++i;}return root;
}//用于检查二叉树是否创建正确
void inorderTraversal(TreeNode *root){if (root==nullptr){return ;}inorderTraversal(root->left);cout<<root->val<<" ";inorderTraversal(root->right);
}//二叉树的最近公共祖先
class Solution
{
public:TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {//遍历到nullptr或者p、 q则返回if (root==nullptr||root==p||root==q) return root;//递归的进行查找TreeNode *left=lowestCommonAncestor(root->left,p,q);TreeNode *right=lowestCommonAncestor(root->right,p,q);//如果当前结点的左右子树都没查找到q或p,则返回nullptrif(left==nullptr&&right==nullptr) return nullptr;//查找到p、q的公共祖先则返回该结点if (left!=nullptr&&right!=nullptr) return root;//p或q存在左子树则返回左子树对应的结点if (left!=nullptr) return left;//p或q存在右子树则返回右子树对应的结点return right; }
};int main(int argc, char const *argv[])
{//-1代表nullvector<int> nums={3,5,1,6,2,0,8,-1,-1,7,4};//通过nums数组创建二叉树TreeNode *root=createTree(nums);//用于检查二叉树是否创建正确//inorderTraversal(root);//计算root->left和root->right的最近公共祖先Solution s;TreeNode *ans = s.lowestCommonAncestor(root,root->left,root->right);cout<<ans->val;return 0;
}
LeetCode 热题 100_二叉树的最近公共祖先(49_236)原题链接
欢迎大家和我沟通交流(✿◠‿◠)
相关文章:

LeetCode 热题 100_二叉树的最近公共祖先(49_236_中等_C++)(二叉树;深度优先搜索)
LeetCode 热题 100_二叉树的最近公共祖先(49_236) 题目描述:输入输出样例:题解:解题思路:思路一(深度优先搜索): 代码实现代码实现(思路一(深度优…...
(三)c#中const、static、readonly的区别
在 C# 中,const、static 和 readonly 都是用来定义不可变的值,但它们有一些关键的区别。让我们详细比较一下这三者的用途和特点: 1. const(常量) 编译时常量:const 用于声明常量,其值必须在编…...

人工智能任务19-基于BERT、ELMO模型对诈骗信息文本进行识别与应用
大家好,我是微学AI,今天给大家介绍一下人工智能任务19-基于BERT、ELMO模型对诈骗信息文本进行识别与应用。近日,演员王星因接到一份看似来自知名公司的拍戏邀约,被骗至泰国并最终被带到缅甸。这一事件迅速引发了社会的广泛关注。该…...

【C++】函数(下)
1、函数的常见样式 常见的函数样式有四种: (1)无参数无返回值 (2)有参数无返回值 (3)无参数有返回值 (4)有参数有返回值 (1)无参数无返回值 示例…...

一个使用 Golang 编写的新一代网络爬虫框架,支持JS动态内容爬取
大家好,今天给大家分享一个由ProjectDiscovery组织开发的开源“下一代爬虫框架”Katana,旨在提供高效、灵活且功能丰富的网络爬取体验,适用于各种自动化管道和数据收集任务。 项目介绍 Katana 是 ProjectDiscovery 精心打造的命令行界面&…...
深入探讨 Vue.js 的动态组件渲染与性能优化
Vue.js 作为一款前端领域中备受欢迎的渐进式框架,以其简单优雅的 API 和灵活性受到开发者的喜爱。在开发复杂应用时,动态组件渲染是一项极其重要的技术,它能够在页面中动态地加载或切换组件,从而显著提升应用的灵活性与用户体验。…...

vulnhub靶场【IA系列】之Tornado
前言 靶机:IA-Tornado,IP地址为192.168.10.11 攻击:kali,IP地址为192.168.10.2 都采用虚拟机,网卡为桥接模式 本文所用靶场、kali镜像以及相关工具,我放置在网盘中,可以复制后面链接查看 htt…...

简要认识JAVAWeb技术三剑客:HTMLCSSJavaScript
目录 一、web标准二、什么是HTML三、什么是CSS四、什么是JavaScript 黑马JAVAWeb飞书在线讲义地址: https://heuqqdmbyk.feishu.cn/wiki/LYVswfK4eigRIhkW0pvcqgH9nWd 一、web标准 Web标准也称网页标准,由一系列的标准组成,大部分由W3C&…...

C# 修改项目类型 应用程序程序改类库
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...

卡通风格渲染
1、卡通风格渲染是什么 卡通风格渲染(Cartoon Shading),也称为非真实感渲染(NPR)或卡通渲染(Toon Shading) 主要目的是使3D模型看起来更像手绘的二维卡通或漫画风格,而不是逼真写实…...
ubuntu各分区的用途
在 Ubuntu 中,分区是将硬盘划分为多个逻辑部分的过程,每个分区可以用于不同的用途。合理分区可以提高系统性能、数据安全性和管理效率。以下是 Ubuntu 中常见分区及其用途的详细说明: 1. 根分区 (/) 用途:存放操作系统核心文件、…...

理解STC15F2K60S2单片机的最小电路
一、STC15F2K60S2与51单片机的区别 STC15F2K60S2和51单片机虽然都基于8051内核,但在多个方面存在显著区别: 1. CPU性能: - STC15F2K60S2:采用增强型8051 CPU,1T单时钟/机器周期,速度比普通8051快8-12倍…...

Docker官网安装
1.官网 官方文档 https://www.docker.com/ Docker Hub官网 镜像 https://hub.docker.com/ 2.Docker 的三要素 1、镜像 2、容器 3、仓库 小总结 3.Docker 平台架构图 (架构版本) 4.安装Docker CentOS | Docker Docs 1.确定你是CentOS7及以上版本 …...

成功案例分享 — 芯科科技助力涂鸦智能打造Matter over Thread模块,简化Matter设备开发
芯科科技(Silicon Labs)的愿景之一是让开发者每天都能够更轻松地开发无线物联网(IoT)。特别是在拥有相同愿景的合作伙伴的帮助下,我们每天都在取得进步。但是要想弥合知识水平和物联网开发之间的差距仍会面临一定的挑战…...

基于Python机器学习、深度学习技术提升气象、海洋、水文领域实践应用-以ENSO预测为例讲解
1. 背景与目标 ENSO(El Nio-Southern Oscillation)是全球气候系统中最显著的年际变率现象之一,对全球气候、农业、渔业等有着深远的影响。准确预测ENSO事件的发生和发展对于减灾防灾具有重要意义。近年来,深度学习技术在气象领域…...

【Rust自学】12.6. 使用TDD(测试驱动开发)开发库功能
12.6.0. 写在正文之前 第12章要做一个实例的项目——一个命令行程序。这个程序是一个grep(Global Regular Expression Print),是一个全局正则搜索和输出的工具。它的功能是在指定的文件中搜索出指定的文字。 这个项目分为这么几步: 接收命令行参数读取…...

贪心算法汇总
1.贪心算法 贪心的本质是选择每一阶段的局部最优,从而达到全局最优。 如何能看出局部最优是否能推出整体最优 靠自己手动模拟,如果模拟可行,就可以试一试贪心策略,如果不可行,可能需要动态规划。 如何验证可不可以…...

H266/VVC 帧内预测中 ISP 技术
帧内子划分 ISP ISP 技术是在 JVET-2002-v3 提案中详细介绍其原理,在 VTM8 中完整展示算法。ISP是线基内预测(LIP)模式的更新版本,它改善了原始方法在编码增益和复杂度之间的权衡,ISP 算法的核心原理就是利用较近的像…...
PyTorch 中的 Dropout 解析
文章目录 一、Dropout 的核心作用数值示例:置零与缩放**训练阶段****推理阶段** 二、Dropout 的最佳使用位置与具体实例解析1. 放在全连接层后2. 卷积层后的使用考量3. BatchNorm 层与 Dropout 的关系4. Transformer 中的 Dropout 应用 三、如何确定 Dropout 的位置…...
集中式架构vs分布式架构
一、集中式架构 如何准确理解集中式架构 1. 集中式架构的定义 集中式架构是一种将系统的所有计算、存储、数据处理和控制逻辑集中在一个或少数几个节点上运行的架构模式。这些中央节点(服务器或主机)作为系统的核心,负责处理所有用户请求和…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...