LeetCode 513.找树左下角的值
LeetCode 513.找树左下角的值
1、题目
题目链接:513. 找树左下角的值
给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
示例 1:

输入: root = [2,1,3]
输出: 1
示例 2:

输入: [1,2,3,4,null,5,6,null,null,7]
输出: 7
提示:
- 二叉树的节点个数的范围是 [1,104]
- -231 <= Node.val <= 231 - 1
2、深度优先搜索(递归)
思路
这道题要在二叉树的 最后一行 找到 最左边的值。
如果使用递归法,如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。所以要找深度最大的叶子节点。
那么如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
我们使用 maxDepth 用来记录最大深度,result 记录最大深度最左节点的数值。
在写递归时,我们要先明确递归三部曲:
- 确定递归函数的参数和返回值
参数必须有要遍历的树的根节点,depth 用来记录当前深度,maxDepth 用来记录最大深度,result 记录最大深度最左节点的数值。 这里就不需要返回值了,所以递归函数的返回类型为 void。
代码如下:
void traversal(TreeNode* root, int depth, int& maxDepth, int& result)
- 确定终止条件
当遇到叶子节点的时候,就需要统计一下最大的深度了,所以需要遇到叶子节点来更新最大深度。
代码如下:
// 如果当前节点是叶子节点
if (root->left == nullptr && root->right == nullptr) {// 如果当前深度大于最大深度if (depth > maxDepth) {// 更新最大深度maxDepth = depth;// 更新结果值为当前节点的值result = root->val;}return;
}
- 确定单层递归的逻辑
在找最大深度的时候,递归的过程中依然要使用回溯。
代码如下:
// 如果左子节点存在
if (root->left) {// 深度加1depth++;// 递归遍历左子树traversal(root->left, depth, maxDepth, result);// 回溯,深度减1depth--;
}
// 如果右子节点存在
if (root->right) {// 深度加1depth++;// 递归遍历右子树traversal(root->right, depth, maxDepth, result);// 回溯,深度减1depth--;
}
代码
#include <iostream>
#include <climits>using namespace std;//Definition for a binary tree node.
struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode() : val(0), left(nullptr), right(nullptr) {}TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};class Solution {
public:void traversal(TreeNode* root, int depth, int& maxDepth, int& result) {// 如果当前节点是叶子节点if (root->left == nullptr && root->right == nullptr) {// 如果当前深度大于最大深度if (depth > maxDepth) {// 更新最大深度maxDepth = depth;// 更新结果值为当前节点的值result = root->val;}return;}// 如果左子节点存在if (root->left) {// 深度加1depth++;// 递归遍历左子树traversal(root->left, depth, maxDepth, result);// 回溯,深度减1depth--;}// 如果右子节点存在if (root->right) {// 深度加1depth++;// 递归遍历右子树traversal(root->right, depth, maxDepth, result);// 回溯,深度减1depth--;}return;}int findBottomLeftValue(TreeNode* root) {if (root == nullptr) {return 0;}// 记录最大深度int maxDepth = INT_MIN;// 记录最大深度最左节点的数值int result = 0;traversal(root, 0, maxDepth, result);return result;}
};int main() {Solution s;TreeNode* root = new TreeNode(3);root->left = new TreeNode(9);root->right = new TreeNode(20);root->right->left = new TreeNode(15);root->right->right = new TreeNode(7);cout << s.findBottomLeftValue(root) << endl;return 0;
}
复杂度分析
- 时间复杂度: O(n),其中 n 是二叉树的节点数目。需要遍历 n 个节点。
- 空间复杂度: O(n)。递归栈需要占用 O(n) 的空间。
3、深度优先搜索(递归精简版)
思路
在回溯的地方可以进行精简,在调用traversal函数时,depth加1,在递归结束时再减1,以确保在递归的不同层次上深度值是正确的。
代码如下:
traversal(root->right, depth + 1, maxDepth, result);
代码
class Solution {
public:void traversal(TreeNode* root, int depth, int& maxDepth, int& result) {// 如果当前节点是叶子节点if (root->left == nullptr && root->right == nullptr) {// 如果当前深度大于最大深度if (depth > maxDepth) {// 更新最大深度maxDepth = depth;// 更新结果值为当前节点的值result = root->val;}return;}// 如果左子节点存在if (root->left) {// 递归遍历左子树,这里隐藏了回溯操作,在调用traversal函数时,depth加1,在递归结束时再减1traversal(root->left, depth + 1, maxDepth, result);}// 如果右子节点存在if (root->right) {// 递归遍历右子树,这里隐藏了回溯操作,在调用traversal函数时,depth加1,在递归结束时再减1traversal(root->right, depth + 1, maxDepth, result);}return;}int findBottomLeftValue(TreeNode* root) {if (root == nullptr) {return 0;}// 记录最大深度int maxDepth = INT_MIN;// 记录最大深度最左节点的数值int result = 0;traversal(root, 0, maxDepth, result);return result;}
};
复杂度分析
- 时间复杂度: O(n),其中 n 是二叉树的节点数目。需要遍历 n 个节点。
- 空间复杂度: O(n)。递归栈需要占用 O(n) 的空间。
4、广度优先搜索(正向层序遍历)
思路
使用广度优先搜索遍历每一层的节点。遍历到最后一行的第一个结点就是要找的结点。
代码
class Solution {
public:int findBottomLeftValue(TreeNode* root) {// 如果根节点为空,返回0if (root == nullptr) {return 0;}// 创建一个队列用于层序遍历queue<TreeNode*> que;// 记录结果int result = 0;// 将根节点入队que.push(root);// 当队列不为空时,进行循环while (!que.empty()) {// 获取当前层的节点个数int size = que.size();// 遍历当前层的节点for (int i = 0; i < size; i++) {// 取出队首节点TreeNode* node = que.front();// 弹出队首节点que.pop();// 如果是当前层的第一个节点,更新结果if (i == 0) {result = node->val;}// 如果该节点有左子节点,将左子节点入队if (node->left) {que.push(node->left);}// 如果该节点有右子节点,将右子节点入队if (node->right) {que.push(node->right);}}}return result;}
};
复杂度分析
- 时间复杂度: O(n)
- 空间复杂度: O(n)
5、广度优先搜索(逆向层序遍历)
思路
使用广度优先搜索遍历每一层的节点。在遍历一个节点时,需要先把它的非空右子节点放入队列,然后再把它的非空左子节点放入队列,这样才能保证从右到左遍历每一层的节点。广度优先搜索所遍历的最后一个节点的值就是最底层最左边节点的值。
代码
class Solution {
public:int findBottomLeftValue(TreeNode* root) {// 如果根节点为空,返回0if (root == nullptr) {return 0;}// 创建一个队列用于层序遍历queue<TreeNode*> que;// 记录结果int result = 0;// 将根节点入队que.push(root);// 当队列不为空时,进行循环while (!que.empty()) {// 获取队首节点TreeNode* node = que.front();que.pop();// 如果该节点有右子节点,将右子节点入队if (node->right) {que.push(node->right);}// 如果该节点有右子节点,将右子节点入队if (node->left) {que.push(node->left);}// 更新结果为当前节点的值result = node->val;}return result;}
};
复杂度分析
- 时间复杂度: O(n)
- 空间复杂度: O(n)
相关文章:
LeetCode 513.找树左下角的值
LeetCode 513.找树左下角的值 1、题目 题目链接:513. 找树左下角的值 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1示例 2: 输入: [1,2,3,4,null…...
redis分片java实践、redis哨兵机制实现、redis集群搭建
redis分片java实践 linux安装redishttps://mp.csdn.net/mp_blog/creation/editor/134864302复制redis.conf配置文件成redis1.conf、redis2.conf、redis3.conf 修改redis的端口信息和存pid文件的路径。存pid文件的路径只要不同就行了,没什么特别要求。 指定配置文件…...
2024年四千价位段最具统治力的投影仪,坚果N1S 4K: 4K+三色激光=下一代4K
更高的亮度与分辨率、更强的对比度、更广的色域、更低的价格,家用智能投影企业在性能和价格上加速内卷。作为该领域的龙头和“卷王之王”,坚果投影率先将激光投影仪的价格拉入万元内,近期其又祭出一把杀手锏——坚果N1S 4K。该产品是首款4000…...
MySQL8.3升级踩坑记录
之前用的mysql5.7,目前被省公司发现有漏洞,需要升级mysql8.3,无奈只好升级,记录下踩坑经过 1、安装完以后设置环境变量,网上操作一大堆,以便于方便使用client 2、双击client 登录,开启远程访问…...
你写的每条SQL都是全表扫描吗
你写的每条SQL都是全表扫描吗?如果是,那MySQL可太感谢你了,每一次SQL执行都是在给MySQL上压力、上对抗。MySQL有苦难言:你不知道索引吗?你写的SQL索引都失效了不知道吗?慢查询不懂啊?建那么多索…...
每日两题 / 24. 两两交换链表中的节点 25. K 个一组翻转链表(LeetCode热题100)
24. 两两交换链表中的节点 - 力扣(LeetCode) 定义三个指针,交换前先保存ntnt指针为next->next,cur和next两个节点,然后将pre->next指向next 若pre为空,说明当前交换的节点为头两个节点,…...
【Linux】模拟实现bash(简易版)
👦个人主页:Weraphael ✍🏻作者简介:目前正在学习c和算法 ✈️专栏:Linux 🐋 希望大家多多支持,咱一起进步!😁 如果文章有啥瑕疵,希望大佬指点一二 如果文章对…...
C++ | Leetcode C++题解之第67题二进制求和
题目: 题解: class Solution { public:string addBinary(string a, string b) {string ans;reverse(a.begin(), a.end());reverse(b.begin(), b.end());int n max(a.size(), b.size()), carry 0;for (size_t i 0; i < n; i) {carry i < a.siz…...
如何确保UDP文件传输工具有最低稳定的传输速度?
在当前日新月异的数字时代背景下,文件传输工具已经成为我们日常生活与工作中不可或缺的一部分,尤其针对那些频繁涉及即时数据交互与多媒体流通的场景。 UDP协议,以其突出的高速传输与低延迟特性,脱颖而出成为众多用户的首选。不过…...
力扣爆刷第133天之动态规划收尾(距离编辑与回文子串)
力扣爆刷第133天之动态规划收尾(距离编辑与回文子串) 文章目录 力扣爆刷第133天之动态规划收尾(距离编辑与回文子串)一、72. 编辑距离二、647. 回文子串三、516. 最长回文子序列 一、72. 编辑距离 题目链接:https://l…...
List集合中对asList的使用
List<String> sArrays.asList(“qwe”,”cvb”,”mnb”); List<String> s1s.subList(1,2); System.out.Pintln(“s”);//输出结果:[qwe,cvb,mnb] System.out.Pintln(“s1”);//输出结果:[cvb] s1.add(“123qwe”);//报错:java…...
软件测试所有测试方法
β测试_Beta测试 β测试,英文是Beta testing。又称Beta测试,用户验收测试(UAT)。 β测试是软件的多个用户在一个或多个用户的实际使用环境下进行的测试。开发者通常不在测试现场,Beta测试不能由程序员或测试员完成。 …...
linux 下 /usr/local的作用
在Linux系统中,/usr/local目录扮演着特定的角色,它是为用户自安装的软件提供一个标准位置。以下是/usr/local目录的主要用途和特点: 用户级程序目录:该目录用于存放用户自行编译安装的软件或者第三方应用程序,区别于操…...
【web网页制作】html+css旅游家乡河南开封主题网页制作(4页面)【附源码】
HTMLCSS家乡河南主题网页目录 🍔涉及知识🥤写在前面🍧一、网页主题🌳二、页面效果Page1 首页Page2 开封游玩Page 3 开封美食Page4 留言 🌈 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 🐋四…...
MySQL用命令行导出数据库
问题: 交作业的时候要求交数据文件,因为用的MySQL数据库,就在想怎么用命令行导出数据库,在csdn上找了其他文章,使用MySQL的命令行用下面语句,结果发生报错 mysqldump -u 用户名 -p 数据库名 > 输出地址…...
uniapp video 层级覆盖
层级覆盖 cover-view组件 我这里做了个判断 监听全屏时隐藏按钮 根据项目需求自行更改...
SparkSQL概述
1.1. SparkSQL介绍 SparkSQL,就是Spark生态体系中的构建在SparkCore基础之上的一个基于SQL的计算模块。SparkSQL的前身不叫SparkSQL,而是叫做Shark。最开始的时候底层代码优化、SQL的解析、执行引擎等等完全基于Hive,总是Shark的执行速度要比…...
docker 和 docker-compose
Docker是一种开源的容器化平台,它可以帮助开发人员将应用程序及其所有依赖项打包到一个独立的、可移植的容器中。这意味着您可以在任何地方运行Docker容器,而不需要担心环境差异或依赖项的问题。 Docker Compose是Docker官方提供的一个工具,…...
微信小程序支付(完整版)-ThinkPHP/Uniapp
技术说明 1.前端:uniapp、vue3 2.接口:PHP8、ThinkPHP8、MySQL8.0 3.微信支付- PHP,官方示例文档 4.示例代码的模型及业务自己进行调整,不要一味的复制粘贴!!! 流程说明 1.小程序调用接口…...
同时安装多个nodejs版本可切换使用,或者用nvm管理、切换nodejs版本(两个详细方法)
目录 一.使用nvm的方法: 1.卸载nodejs 2.前往官网下载nvm 3.安装nvm 4.查看安装是否完成 5.配置路径和淘宝镜像 6.查看和安装各个版本的nodejs 7.nvm的常用命令 二.不使用nvm,安装多个版本: 1.安装不同版本的nodejs 2.解压到你想放…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
<6>-MySQL表的增删查改
目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表…...
关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
