C++ 队列 宽度优先搜索 BFS 力扣 515. 在每个树行中找最大值 每日一题

C++ 队列 宽度优先搜索 BFS 力扣 515. 在每个树行中找最大值 每日一题

文章目录

在这里插入图片描述

在这里插入图片描述

一、题目描述

题目链接:力扣 515. 在每个树行中找最大值

题目描述:

给你一棵二叉树的根节点 ,请你找出每一层的最大值,并按层的顺序返回这些最大值组成的数组。
示例 1:

输入:root = [1,3,2,5,3,null,9]
输出:[1,3,9]
示例 2:
输入:root = [1,2,3]
输出:[1,3]
提示:
树中节点数目在范围 [0, 10⁴] 内
-2³¹ <= Node.val <= 2³¹ - 1

二、为什么这道题值得你花几分钟弄懂?

这道题是BFS层序遍历的经典进阶应用,是大厂面试中考察“分层遍历+层内统计”的高频题。它在基础层序遍历的核心逻辑上,增加了“层内最大值统计”的规则,既能检验我们对BFS分层逻辑的掌握程度,又能考察我们在遍历过程中进行数值计算的能力,是夯实树遍历基础、提升逻辑拓展能力的必做题。

题目核心价值:

  • 基础能力的延伸:在二叉树层序遍历的“分层”核心上,新增“层内极值统计”逻辑,检验我们是否真正理解分层遍历的本质,而非死记硬背代码。
  • 逻辑灵活性的体现:同一套BFS框架下,仅通过简单的“层内值比较+最大值记录”就能实现需求,训练我们“在通用框架上定制化需求”的思维。
  • 面试的“基础筛选题”:基础层序遍历是入门题,而层内找最大值是基础题的变形,能区分“只会写固定代码”和“能灵活调整逻辑”的候选人。
  • 边界场景的再训练:同样需要处理空树、单节点树、满二叉树等场景,进一步强化我们考虑问题的全面性。
  • 代码简洁性的平衡:在不破坏BFS核心逻辑的前提下,用最少的代码实现层内最大值统计,契合面试中“简洁且易读”的代码评分标准。

面试考察的核心方向:

  1. BFS分层逻辑的迁移能力:能否将基础层序遍历的思路无缝迁移,并适配“层内统计”的需求。
  2. 逻辑拓展能力:能否在基础遍历逻辑上,快速添加“层内最大值初始化+逐值比较”的拓展逻辑。
  3. 数值边界处理:是否能意识到用INT_MIN初始化最大值的合理性,以及处理负数节点值的场景。
  4. 复杂度分析:能否准确分析算法的时间和空间复杂度,理解“层内比较”不会增加整体时间复杂度。

掌握这道题,既能巩固BFS分层遍历的核心,又能训练“基础逻辑+定制化统计”的解题思路。

在这里插入图片描述

三、算法原理

本题的核心算法是 “基于队列的BFS分层遍历 + 层内最大值统计”,在基础层序遍历的框架上,仅增加“层内最大值初始化”和“逐节点值比较更新最大值”两步操作,逻辑清晰且易于理解。

  1. 初始化一个队列,把二叉树的根节点入队(若根节点为空,直接返回空结果)。
  2. 初始化一个结果数组,用于存储每一层的最大值。
  3. 当队列不为空时,执行以下操作:
    • 记录当前队列的大小(即当前层的节点数n)。
    • 初始化当前层的最大值变量max_val为整型最小值(INT_MIN),确保能覆盖所有节点值的边界情况。
    • 循环n次,依次取出队列头部的节点:
      • 将当前节点值与max_val比较,更新max_val为两者中的较大值。
      • 若节点有左子节点,将左子节点入队;若有右子节点,将右子节点入队(为下一层遍历做准备)。
    • 将当前层的最大值max_val加入结果数组。
  4. 队列为空时,遍历完成,返回最终结果数组。

这个思路的本质是:用BFS完成分层遍历,在遍历每一层的过程中同步统计最大值,以最小的代码改动适配“层内找最大值”的需求

模拟过程

我们用示例1完整模拟,帮你直观理解每一步的队列状态和最大值统计过程。

场景:示例1 二叉树 [1,3,2,5,3,null,9]
初始状态:

  • 队列 q = [1]
  • 最终结果 ret = []
步骤队列状态当前层节点数(n)当前层最大值(max_val)节点值比较过程ret变化
1[1]111 → max_val=1[1]
2[3,2]233→max_val=3 → 2→max_val保持3[1,3]
3[5,3,9]395→max_val=5 → 3→max_val保持5 → 9→max_val=9[1,3,9]
4[]0-队列空,结束遍历不变

细节注意

  1. 最大值初始化:必须用INT_MIN(需包含<climits>头文件)初始化,不能用0,否则无法正确处理全负数的二叉树(比如节点值为[-5,-3,-8]的情况)。
  2. 子节点入队顺序:二叉树层序遍历需先入队左子节点、再入队右子节点,不影响最大值统计,但这是层序遍历的标准操作。
  3. 边界条件:空树直接返回空数组,避免后续操作空指针;单节点树直接返回[val],无需额外处理。

常见错误与避坑

  1. 最大值初始化错误:二叉树节点的取值是有负数的,用0或1初始化最大值,会导致全负数节点的二叉树统计结果错误。
  2. 忘记处理空树:直接操作空根节点会触发空指针异常。
  3. 层内节点数获取时机错误:在循环过程中获取队列大小,而非循环前,导致统计的节点数混入下一层节点。
  4. 最大值更新逻辑错误:在节点入队后才更新最大值,导致当前节点值未被统计。

四、代码实现

/** * 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) {} * }; */#include<vector>#include<queue>#include<climits>// 包含INT_MIN所需的头文件usingnamespace std;classSolution{public: vector<int>largestValues(TreeNode* root){// 存储每一层的最大值 vector<int> ret;// 边界条件:空树直接返回空数组if(root ==nullptr)return ret;// 标准队列存储二叉树节点,效率优于vector模拟 queue<TreeNode*> q; q.push(root);// 队列非空则继续遍历while(!q.empty()){// 记录当前层的节点数(循环前获取,避免混入下一层节点)int n = q.size();// 初始化当前层最大值为整型最小值,覆盖所有数值边界int max_val = INT_MIN;// 遍历当前层的所有节点for(int i =0; i < n; i++){// 取出队头节点 TreeNode* tmp = q.front(); q.pop();// 核心:更新当前层的最大值 max_val =max(max_val, tmp->val);// 二叉树子节点入队:先左后右,保证层序遍历顺序if(tmp->left !=nullptr) q.push(tmp->left);if(tmp->right !=nullptr) q.push(tmp->right);}// 将当前层的最大值加入结果数组 ret.push_back(max_val);}return ret;}};

代码细节说明

  1. 队列的实现:使用C++标准库的queue<TreeNode*>push入队、front()取队头、pop()出队),相比vector模拟队列效率更高(queuepop操作时间复杂度为O(1))。
  2. 核心逻辑
    • 外层while循环:控制层的遍历,队列非空则继续;
    • 内层for循环:遍历当前层的所有节点,逐值比较更新最大值,并将子节点入队;
    • 最大值统计:用max函数比较当前节点值和已记录的最大值,确保每一层能找到最大的节点值。
  3. 数值边界处理:用INT_MIN初始化最大值,确保能正确处理节点值为负数的场景(比如节点值为[-1,-2,-3]时,仍能统计出-1作为第一层最大值)。

复杂度分析

  • 时间复杂度:O(n)。n是二叉树的节点数,每个节点入队、出队各一次(O(n));层内最大值比较操作总次数为O(n)(每个节点仅参与一次比较),因此整体时间复杂度仍为O(n)。
  • 空间复杂度:O(n)。最坏情况下(完美二叉树的最后一层),队列存储的节点数为n/2,空间复杂度为O(n);结果数组存储每一层的最大值,空间复杂度为O(h)(h为树的高度),整体空间复杂度为O(n)。

五、总结

  1. 核心逻辑:BFS分层遍历 + 层内最大值统计是解决本题的核心,在遍历每一层节点的过程中同步更新最大值是最高效的方式。
  2. 细节要点:用INT_MIN初始化层内最大值以覆盖负数场景,层内节点数需在循环前获取,子节点需“先左后右”入队。
  3. 代码优化:标准库queuevector模拟队列效率更高,层内比较操作不影响整体时间复杂度。

六、下题预告

下一篇我们一起学习优先级队列(堆)在算法题中的应用,攻克 力扣 1046. 最后一块石头的重量

喵~ 能啃完这道二叉树最大宽度喵,宝子你真的真的真的很棒喵~😼 要是对分层统计的逻辑、队列操作的时机还有小疑问喵,或者有更丝滑的解题思路喵,都可以甩到评论区喵,我看到会第一时间把问题给这个博主的喵~

别忘了点个赞、关个注~(๑˃̵ᴗ˂̵)و 你的支持就是博主继续肝优质算法内容的最大动力喵~我们下道题,不见不散喵~

在这里插入图片描述

Read more

【C++】 —— 笔试刷题day_18

【C++】 —— 笔试刷题day_18

一、压缩字符串(一) 题目解析 题目给定一个字符str,让我们将这个字符串进行压缩; **压缩规则:**出现多次的字符压缩成字符+数字;例如aaa压缩成a3。如果字符值出现一次,1不用写。 算法思路 这道题总的来说就非常简单了,我们直接模拟整个过程即可。 思路: 示例双指针遍历,统计字符和字符出现的次数; i固定一个字符,j向后遍历找与i位置相同的字符,如果相同就继续向后遍历,直到j位置与i位置的字符不相同; j向后遍历结束,i位置字符出现的字符次数为j-i;如果j-1大于1就在结果字符串中加入出现的次数;等于1则不用加次数。 代码实现 classSolution{public: string compressString(string param){ string ret;for(int i =0;i<param.size();){int j = i+1;while(j<

By Ne0inhk
RabbitMQ如何成为分布式系统的“神经中枢“?——从安装部署到C++调用实战的完整流程,带你体验它的奥妙所在!​

RabbitMQ如何成为分布式系统的“神经中枢“?——从安装部署到C++调用实战的完整流程,带你体验它的奥妙所在!​

文章目录 * 本篇摘要 * ①·RabbitMq(轻量级消息队列中间件) 介绍 * RabbitMQ 是什么? * 核心功能与特点 * 1. **核心功能** * 2. **核心优势** * RabbitMQ 的核心概念 * 1. **生产者(Producer)** * 2. **消费者(Consumer)** * 3. **队列(Queue)** * 4. **交换机(Exchange)** * 5. **绑定(Binding)** * 工作流程(以 Direct 交换机为例) * 常见应用场景 * RabbitMQ 与相关技术对比 * 图像理解 * 总结一句话 * ②·RabbitMq 安装教程 * RabbitMq安装 * **1. 安装 RabbitMQ** * **2. 启动 & 检查状态** * **3. 创建管理员用户(

By Ne0inhk
C++性能优化:提升代码执行效率的艺术

C++性能优化:提升代码执行效率的艺术

C++性能优化:提升代码执行效率的艺术 一、学习目标与重点 本章将深入探讨C++性能优化的核心知识,帮助你掌握提升代码执行效率的艺术。通过学习,你将能够: 1. 理解性能优化的基本概念,掌握性能分析的方法 2. 学会优化内存管理,减少内存泄漏和内存碎片 3. 理解CPU优化技巧,提高代码的执行速度 4. 学会优化I/O操作,提升文件和网络读写的效率 5. 培养性能优化思维,设计高效的代码 二、性能优化的基本概念 2.1 性能优化的原则 性能优化应该遵循以下原则: * 先测量后优化:在优化之前,必须先测量代码的性能,找出瓶颈所在 * 优化瓶颈:只优化对性能影响最大的部分 * 保持代码的可维护性:优化后的代码应该易于理解和维护 * 测试优化结果:优化后必须测试代码的正确性和性能提升效果 2.2 性能分析工具 常用的性能分析工具包括: * GProf:GNU的性能分析工具 * Valgrind:内存调试和性能分析工具

By Ne0inhk
深入解剖STL map/multimap:接口使用与核心特性详解

深入解剖STL map/multimap:接口使用与核心特性详解

❤️@燃于AC之乐 来自重庆 计算机专业的一枚大学生 ✨专注 C/C++ Linux 数据结构 算法竞赛 AI 🏞️志同道合的人会看见同一片风景! 👇点击进入作者专栏: 《算法画解》 ✅ 《linux系统编程》✅ 《C++》 ✅ 🌟《算法画解》算法相关题目点击即可进入实操🌟 感兴趣的可以先收藏起来,请多多支持,还有大家有相关问题都可以给我留言咨询,希望希望共同交流心得,一起进步,你我陪伴,学习路上不孤单! 文章目录 * 前言(map系列容器概述) * 一、map类介绍 * 1.1 map的类模板声明 * 二、pair类型介绍 * 2.1 pair的结构定义 * 2.2 pair的使用要点 * 三、map的构造与迭代器 * 3.1 构造接口 * 3.2 迭代器接口 * 四、map的增删查操作

By Ne0inhk