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

【LeetCode热题100道笔记】二叉树的层序遍历

题目描述

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

示例 1:
在这里插入图片描述
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]

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

示例 3:
输入:root = []
输出:[]

提示:
树中节点数目在范围 [0, 2000] 内
-1000 <= Node.val <= 1000

思考:基础BFS实现(队列存储整层节点)

核心是用队列维护当前层节点,每次遍历完当前层所有节点后,收集下一层节点,循环直至队列为空。

算法过程

  1. 边界处理:若根节点rootnull(空树),直接返回空数组。
  2. 初始化:创建结果数组result(存储每层节点值),队列queue初始存入根节点(第一层仅根节点)。
  3. 层序循环(遍历每一层)
    • 收集当前层值:将队列中所有节点的val提取为子数组,加入result
    • 收集下一层节点:创建临时数组tmp,遍历当前层所有节点,若节点有左/右子节点,依次加入tmp
    • 更新队列:将队列替换为tmp(下一层节点),进入下一轮循环,直至队列为空。
  4. 返回结果:返回result,即按层排列的节点值二维数组。

时空复杂度

  • 时间复杂度:O(n),n为二叉树节点总数。
    原因:每个节点仅入队、出队各1次,提取节点值的操作也为O(n),总操作次数与节点数线性相关。
  • 空间复杂度:O(m),m为二叉树最宽层的节点数。
    原因:队列需存储当前层所有节点,最坏情况(完全二叉树最后一层)m=O(n/2)=O(n),最好情况(链状树)m=1。

基础代码

/*** Definition for a binary tree node.* function TreeNode(val, left, right) {*     this.val = (val===undefined ? 0 : val)*     this.left = (left===undefined ? null : left)*     this.right = (right===undefined ? null : right)* }*/
/*** @param {TreeNode} root* @return {number[][]}*/
var levelOrder = function(root) {if (!root) return []; // 空树直接返回const result = []; // 存储最终层序结果let queue = [root]; // 队列:维护当前层节点while (queue.length) {// 1. 收集当前层所有节点的valresult.push(queue.map(node => node.val));// 2. 收集下一层节点(左子节点优先)let tmp = [];for (let node of queue) {if (node.left) tmp.push(node.left);if (node.right) tmp.push(node.right);}// 3. 切换到下一层queue = tmp;}return result;
};

思考:优化BFS实现(单队列+指针避免临时数组)

基础实现中,每次收集下一层节点需创建临时数组tmp,优化思路是用“队列指针”标记当前层边界:通过front指针记录已处理的节点位置,计算当前层节点数,直接在原队列中遍历当前层、添加下一层节点,避免临时数组开销。

算法过程

  1. 边界处理:同基础实现,空树返回空数组。
  2. 初始化:结果数组ret,队列q初始存入根节点,front指针初始为0(标记队列中未处理节点的起始位置)。
  3. 层序循环(按指针控制层边界)
    • 计算当前层节点数:当前层节点数 = 队列总长度 - front(排除已处理的上层节点);
    • 初始化当前层子数组:在ret中新增一个空数组,用于存储当前层节点值;
    • 遍历当前层节点:循环currentLevelSize次:
      • 取队列中front位置的节点(当前待处理节点),front指针后移(标记为已处理);
      • 将节点val加入ret的最后一个子数组(当前层);
      • 若节点有左/右子节点,直接加入队列尾部(下一层节点);
  4. 返回结果:返回ret

时空复杂度

  • 时间复杂度:O(n),与基础实现一致,每个节点仅处理1次。
  • 空间复杂度:O(m),与基础实现一致(队列存储节点数不变),但减少了临时数组tmp的额外空间(基础实现的tmp最多存储m个节点,优化后直接复用原队列,空间更紧凑)。

优化代码

/*** Definition for a binary tree node.* function TreeNode(val, left, right) {*     this.val = (val===undefined ? 0 : val)*     this.left = (left===undefined ? null : left)*     this.right = (right===undefined ? null : right)* }*/
/*** @param {TreeNode} root* @return {number[][]}*/
var levelOrder = function(root) {const ret = [];if (!root) return ret;const q = [root]; // 单队列存储所有待处理节点let front = 0; // 指针:标记已处理节点的边界while (front < q.length) {// 1. 计算当前层节点数(队列中未处理的节点数)const currentLevelSize = q.length - front;// 2. 初始化当前层子数组ret.push([]);// 3. 遍历当前层所有节点for (let i = 0; i < currentLevelSize; i++) {const node = q[front++]; // 取当前节点,指针后移(O(1)操作)ret[ret.length - 1].push(node.val); // 存入当前层值// 4. 下一层节点直接加入队列尾部if (node.left) q.push(node.left);if (node.right) q.push(node.right);}}return ret;
};

基础实现与优化实现对比

维度基础实现优化实现
核心逻辑队列存当前层,临时数组存下一层单队列+指针,标记层边界
空间开销需额外临时数组tmp复用原队列,无临时数组
时间效率O(n)O(n)(操作更紧凑)
代码复杂度简单直观需理解指针与层边界关系

适用场景

  • 基础实现适合代码简洁性优先的场景,逻辑易理解;
  • 优化实现适合空间敏感场景,尤其在节点数较多时,可减少临时数组的内存占用。
http://www.xdnf.cn/news/1476325.html

相关文章:

  • RTU(远程终端单元)​​ 和 ​​PLC(可编程逻辑控制器)
  • 《AC影》正史模式引争议 育碧回应希望激发历史兴趣
  • 【CF】Day139——杂题 (绝对值变换 | 异或 + 二分 | 随机数据 + 图论)
  • 《用 Python 构建并发 API 爬虫:从基础到高性能实战》
  • Python爬虫实战:研究Axis Artist模块,构建电商数据采集和分析系统
  • Go语言设计模式(三)抽象工厂模式
  • ModelScope概述与实战
  • GitHub 热榜项目 - 日榜(2025-09-06)
  • PowerBI TopN Others
  • tp报错解决
  • 【Gigascience】时空转录组测序探索小鼠心脏发育的细胞与分子基础
  • 留数法分解有理分式
  • Rust在医疗系统中的应用:安全、性能与合规性实践(上)
  • 3.进程调度:常见算法
  • leetcode30.串联所有单词的子串
  • [数据结构] LinkedList
  • c++之基础B(x转10进制,含十六进制)(第四课)
  • 7.网络虚拟化
  • 【开题答辩全过程】以 基于Hadoop电商数据的可视化分析为例,包含答辩的问题和答案
  • Lua和C#比较
  • 分布式go项目-搭建监控和追踪方案补充-ELK日志收集
  • OpenHarmony之有源NFC-connected_nfc_tag模块详解
  • LangChain实战(十八):构建ReAct模式的网页内容摘要与分析Agent
  • 同一台nginx中配置多个前端项目的三种方式
  • 贪心算法在脑机接口解码问题中的应用
  • qiankun 微前端接入实战
  • 在线教育系统源码选型指南:功能、性能与扩展性的全面对比
  • import type在模块引入中的作用
  • 从“能说话”到“会做事”:AI工具如何重塑普通人的工作与生活?
  • 语义切片技术深度解析:重新定义RAG时代的文本处理范式