102. 二叉树的层序遍历递归法:深度优先搜索的巧妙应用

news2025/5/20 18:26:26

二叉树的层序遍历是一种经典的遍历方式,它要求按层级逐层访问二叉树的节点。通常我们会使用队列来实现层序遍历,但递归法也是一种可行且有趣的思路。本文将深入探讨递归法解决二叉树层序遍历的核心难点,并结合代码和模拟过程进行详细讲解。

一、题目描述

给定一个二叉树的根节点 root,返回其节点值的层序遍历结果,即逐层遍历,从左到右访问所有节点。例如,输入二叉树:

    3
   / \
  9  20
    /  \
   15   7

输出结果应为:
[[3], [9, 20], [15, 7]]

二、核心难点分析

难点1:临时数组的创建逻辑

在递归法中,我们需要预先创建好数组来存储每一层的节点值。这里的关键是如何根据当前节点的深度(层级)来确定将节点值存储到哪个数组中。

  • 深度标记
    我们使用一个变量 deep 来表示当前节点所在的深度。初始时,根节点的深度为 1
  • 数组创建与填充
    在递归过程中,每当遇到一个新的深度 deep 时,我们需要确保 res 中已经有足够的子列表来存储该层的节点值。如果 res 的大小小于 deep,则创建一个新的空列表并添加到 res 中。然后,将当前节点的值添加到 res 中对应深度的子列表中。

难点2:递归的具体逻辑实现

递归法的核心在于如何通过递归调用自身来遍历二叉树的每一层。

  • 递归终止条件
    当遇到 null 节点时,递归结束。这是因为 null 节点没有值,也没有子节点,不需要进行任何处理。
  • 递归调用
    对于每个非 null 节点,我们先将其值添加到对应深度的子列表中,然后分别对其左子节点和右子节点进行递归调用。在递归调用时,深度 deep 需要加 1,以表示进入了下一层。

三、解题思路分步解析

步骤1:初始化结果列表和递归调用

public List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> res = new ArrayList<>();
    levelOrderBFS(res, root, 0);
    return res;
}

这里我们首先创建了一个空的结果列表 res,然后调用递归函数 levelOrderBFS 开始遍历。初始深度设为 0,因为在递归函数内部会先将深度加 1 再进行处理。

步骤2:递归函数实现

public void levelOrderBFS(List<List<Integer>> res, TreeNode root, int deep) {
    if (root == null) {
        return;
    }
    deep++;
    while (res.size() < deep) {
        List<Integer> resList = new ArrayList<>();
        res.add(resList);
    }
    res.get(deep - 1).add(root.val);
    levelOrderBFS(res, root.left, deep);
    levelOrderBFS(res, root.right, deep);
}
  • 深度处理
    首先将深度 deep1,因为当前节点的深度比其父节点大 1
  • 数组创建与填充
    使用 while 循环检查 res 的大小是否小于 deep。如果是,则创建一个新的空列表 resList 并添加到 res 中。这确保了 res 中始终有足够的子列表来存储每一层的节点值。
    然后,通过 res.get(deep - 1).add(root.val) 将当前节点的值添加到 res 中对应深度的子列表中。
  • 递归调用
    最后,分别对当前节点的左子节点和右子节点进行递归调用,深度 deep 保持不变。这使得递归能够逐层深入,遍历整个二叉树。

四、递归流程模拟

以二叉树 [3, 9, 20, null, null, 15, 7] 为例,结构如下:

    3
   / \
  9  20
    /  \
   15   7

以下是递归过程的详细模拟:

初始状态

res = []deep = 0root = 3

第一次递归调用

  • deep = 1
  • res.size() = 0 < 1,创建新列表 [] 并添加到 res 中,此时 res = [[]]
  • 3 添加到 res[0] 中,此时 res = [[3]]
  • root.left(即 9)进行递归调用,deep = 1
  • root.right(即 20)进行递归调用,deep = 1

9 的递归调用

  • deep = 2
  • res.size() = 1 < 2,创建新列表 [] 并添加到 res 中,此时 res = [[3], []]
  • 9 添加到 res[1] 中,此时 res = [[3], [9]]
  • root.left(即 null)进行递归调用,deep = 2
  • root.right(即 null)进行递归调用,deep = 2

20 的递归调用

  • deep = 2
  • res.size() = 2 == 2,直接将 20 添加到 res[1] 中,此时 res = [[3], [9, 20]]
  • root.left(即 15)进行递归调用,deep = 2
  • root.right(即 7)进行递归调用,deep = 2

15 的递归调用

  • deep = 3
  • res.size() = 2 < 3,创建新列表 [] 并添加到 res 中,此时 res = [[3], [9, 20], []]
  • 15 添加到 res[2] 中,此时 res = [[3], [9, 20], [15]]
  • root.left(即 null)进行递归调用,deep = 3
  • root.right(即 null)进行递归调用,deep = 3

7 的递归调用

  • deep = 3
  • res.size() = 3 == 3,直接将 7 添加到 res[2] 中,此时 res = [[3], [9, 20], [15, 7]]
  • root.left(即 null)进行递归调用,deep = 3
  • root.right(即 null)进行递归调用,deep = 3

最终结果

res = [[3], [9, 20], [15, 7]]

五、关键知识点总结

1. 递归的基本概念

递归是一种解决问题的方法,它通过将问题分解为更小的子问题,并通过调用自身来解决这些子问题。在二叉树的层序遍历中,我们通过递归调用自身来遍历每一层的节点。

2. 深度优先搜索(DFS)与广度优先搜索(BFS)

递归法本质上是一种深度优先搜索(DFS)的应用。与广度优先搜索(BFS)不同,DFS会沿着一条路径一直深入下去,直到无法继续,然后再回溯到上一层,继续探索其他路径。在层序遍历中,我们通过递归实现了一种特殊的DFS,它能够逐层遍历二叉树的节点。

3. 动态数组的使用

在递归过程中,我们使用了一个动态数组 res 来存储每一层的节点值。动态数组的特点是可以根据需要动态地增加或减少元素,这使得我们能够灵活地处理不同层级的节点数量。

六、完整代码

import java.util.ArrayList;
import java.util.List;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

class Solution {
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        levelOrderBFS(res, root, 0);
        return res;
    }

    public void levelOrderBFS(List<List<Integer>> res, TreeNode root, int deep) {
        if (root == null) {
            return;
        }
        deep++;
        while (res.size() < deep) {
            List<Integer> resList = new ArrayList<>();
            res.add(resList);
        }
        res.get(deep - 1).add(root.val);
        levelOrderBFS(res, root.left, deep);
        levelOrderBFS(res, root.right, deep);
    }
}

七、总结

递归法解决二叉树的层序遍历问题虽然不像队列法那样直观,但它展示了深度优先搜索在树形结构中的巧妙应用。通过理解临时数组的创建逻辑和递归的具体实现,我们能够更好地掌握递归的思想和技巧。在实际应用中,递归法可能在某些情况下比队列法更简洁高效,尤其是对于一些复杂的树形结构或需要深度优先处理的问题。希望本文的讲解能够帮助读者更好地理解和掌握递归法解决二叉树层序遍历的核心难点。

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

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

相关文章

第31讲 循环缓冲区与命令解析

串口在持续接收数据时容易发生数据黏包&#xff08;先接收的数据尚未被处理&#xff0c;后面的数据已经将内存覆盖&#xff09;的情况&#xff0c;循环缓冲区的本质就是将串口接受到的数据马上拷贝到另外一块内存之中。为了避免新来的数据覆盖掉尚未处理的数据&#xff0c;一方…

数据结构(十)——排序

一、选择排序 1.简单选择排序 基本思想&#xff1a;假设排序表为[1,…,n]&#xff0c;第i趟排序即从[i,…,n]中选择关键字最小的元素与L[i]交换 eg&#xff1a;给定关键字序列{87&#xff0c;45&#xff0c;78&#xff0c;32&#xff0c;17&#xff0c;65&#xff0c;53&…

美蛋工具箱:一站式解决图片、视频、音频和文档处理需求的聚合神器

先放下载链接:夸克网盘下载 宝子们&#xff0c;今天不啰嗦&#xff0c;直接给大家安利一款超好用的聚合工具&#xff0c;有需要的小伙伴赶紧码住&#xff01; 今天要介绍的这款工具叫美蛋工具箱&#xff0c;它是一款聚合类工具。这个软件是绿色版的&#xff0c;聚合了图片工具…

python打卡day16

NumPy 数组基础 因为前天说了shap&#xff0c;这里涉及到数据形状尺寸问题&#xff0c;所以需要在这一节说清楚&#xff0c;后续的神经网络我们将要和他天天打交道。 知识点&#xff1a; numpy数组的创建&#xff1a;简单创建、随机创建、遍历、运算numpy数组的索引&#xff1a…

Redis 学习笔记 5:分布式锁

Redis 学习笔记 5&#xff1a;分布式锁 在前文中学习了如何基于 Redis 创建一个简单的分布式锁。虽然在大多数情况下这个锁已经可以满足需要&#xff0c;但其依然存在以下缺陷&#xff1a; 事实上一般而言&#xff0c;我们可以直接使用 Redisson 提供的分布式锁而非自己创建。…

游戏开发实战(一):Python复刻「崩坏星穹铁道」嗷呜嗷呜事务所---源码级解析该小游戏背后的算法与设计模式【纯原创】

文章目录 奇美拉项目游戏规则奇美拉(Chimeras)档案领队成员 结果展示&#xff1a; 奇美拉项目 由于项目工程较大&#xff0c;并且我打算把我的思考过程和实现过程中踩过的坑都分享一下&#xff0c;因此会分3-4篇博文详细讲解本项目。本文首先介绍下游戏规则并给出奇美拉档案。…

02- 浏览器运行原理

文章目录 1. 网页的解析过程浏览器内核 2. 浏览器渲染流程2.1 解析html2.2 生成css规则2.3 构建render tree2.4 布局(Layout)2.5 绘制(Paint) 3. 回流和重绘3.1 回流reflow&#xff08;1&#xff09;理解&#xff1a;&#xff08;2&#xff09;出现情况 3.2 重绘repaint&#x…

移除链表元素数据结构oj题(力扣题206)

目录 题目描述&#xff1a; 题目解读&#xff08;分析&#xff09; 解决代码 题目描述&#xff1a; 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 题目解读&#xff08;分析&#…

OpenTelemetry 从入门到精通

快速入门 OpenTelemetry 是一个可观测性框架和工具包&#xff0c; 旨在创建和管理遥测数据&#xff0c;如链路、 指标和日志。 重要的是&#xff0c;OpenTelemetry 是供应商和工具无关的&#xff0c;这意味着它可以与各种可观测性后端一起使用&#xff0c; 包括 Jaeger 和 Pro…

【免杀】C2免杀技术(六)进程镂空(傀儡进程)

一、技术定位与核心思想 进程镂空&#xff08;Process Hollowing&#xff09;属于 MITRE ATT&CK 中 T1055.012 子技术&#xff1a;先创建一个合法进程并挂起&#xff0c;随后把其主模块从内存“掏空”并替换为恶意映像&#xff0c;最后恢复线程执行&#xff0c;从而让…

Eclipse Java 开发调优:如何让 Eclipse 运行更快?

Eclipse Java 开发调优&#xff1a;如何让 Eclipse 运行更快&#xff1f; 在 Java 开发领域&#xff0c;Eclipse 是一款被广泛使用的集成开发环境&#xff08;IDE&#xff09;。然而&#xff0c;随着项目的日益庞大和复杂&#xff0c;Eclipse 的运行速度可能会逐渐变慢&#x…

彻底理解事件循环(Event Loop):从单线程到异步世界的桥梁

关于事件循环被问了很多次&#xff0c;也遇到过很多次&#xff0c;一直没有系统整理&#xff0c;网上搜的&#xff0c;基本明白但总感觉不够透彻&#xff0c;最后&#xff0c;自己动手&#xff0c;丰衣足食&#xff0c;哈哈 一、为什么需要事件循环&#xff1f;—— 单线程的困…

Linux(2)——shell原理及Linux中的权限

目录 一、shell的运行原理 二、Linux中权限的问题 1.权限的概念 2.如何进行用户的切换 1&#xff09;从普通用户切到超级用户 2&#xff09;从root用户切到普通用户 3.如何实现提权操作 4.如何将普通用户添加到信用列表&#xff08;sudoers&#xff09; ​编辑5.Lin…

如何在线免费压缩PDF文档?

PDF文件太大&#xff0c;通常是因为内部嵌入字体和图片。怎么才能将文件大小减减肥呢&#xff0c;主要有降低图片清晰度和去除相关字体两个方向来实现文档效果。接下来介绍三个免费压缩PDF实用工具。 &#xff08;一&#xff09;iLoveOFD在线转换工具 iLoveOFD在线转换工具&a…

汽车装配又又又升级,ethernetip转profinet进阶跃迁指南

1. 场景描述&#xff1a;汽车装配线中&#xff0c;使用EtherNet/IP协议的机器人与使用PROFINET协议的PLC进行数据交互。 2. 连接设备&#xff1a;EtherNet/IP机器人控制器&#xff08;如ABB、FANUC&#xff09;与PROFINET PLC&#xff08;如西门子S7-1500&#xff09;。 3. 连…

css:无限滚动波浪线

以上是需要实现的效果&#xff0c;一条无限滚动波浪线&#xff0c;可以用来做区块的分割线。 要形成上下交替的圆形&#xff0c;思路是给div加圆角边框&#xff0c;第一个只有上边框&#xff0c;第二个只有下边框。 循环了100个div&#xff0c;这个数量根据自己容器宽度调整&…

w~自动驾驶~合集3

我自己的原文哦~ https://blog.51cto.com/whaosoft/13269720 #FastOcc 推理更快、部署友好Occ算法来啦&#xff01; 在自动驾驶系统当中&#xff0c;感知任务是整个自驾系统中至关重要的组成部分。感知任务的主要目标是使自动驾驶车辆能够理解和感知周围的环境元素&…

山东大学计算机图形学期末复习整理5——CG10上

CG10上 Frenet-Serret框架 空间中一条曲线可以写成参数形式&#xff1a; C ( u ) ( x ( u ) , y ( u ) , z ( u ) ) \mathbf{C}(u) (x(u), y(u), z(u)) C(u)(x(u),y(u),z(u)) 这表示&#xff1a;当参数 u u u 变化时&#xff0c;曲线在三维空间中移动&#xff0c;生成一条轨…

STM32移植LVGL8.3 (保姆级图文教程)

目录 前言设备清单2.8寸TFT-LCD屏原理与应用1️⃣基本参数2️⃣引脚说明3️⃣程序移植4️⃣硬件接线 LVGL8.3 移植流程1️⃣硬件及平台要求2️⃣版本说明3️⃣源码下载4️⃣源码移植 工程配置修改配置文件1️⃣lvgl_config.h2️⃣适配屏幕驱动3️⃣配置输入设备(触摸功能) 提供…

虚幻引擎5-Unreal Engine笔记之Default Pawn与GamMode、Camera的关系

虚幻引擎5-Unreal Engine笔记之Default Pawn与GamMode、Camera的关系 code review! 文章目录 虚幻引擎5-Unreal Engine笔记之Default Pawn与GamMode、Camera的关系1.Default Pawn与Camera的关系1.1. Default Pawn 是什么&#xff1f;1.2. Default Pawn 的主要组件1.3. Default…