【Leetcode】十六、深度优先搜索 宽度优先搜索 :二叉树的层序遍历
文章目录
- 1、深度优先搜索算法
- 2、宽度优先搜索算法
- 3、leetcode102:二叉树的层序遍历
- 4、leetcode107:二叉树的层序遍历II
- 5、leetcode938:二叉搜索树的范围和
1、深度优先搜索算法
深度优先搜索,即DFS,从root节点开始,尽可能深的搜索每一个分支。把一个分支的结果搜索完以后,再去看下一个分支。

应用场景:
- 二叉树搜索
- 图搜索
例子:走迷宫,从起点开始,一直走到终点或者撞墙后(这就是所谓的 “深度” 优先),回到起点重新开始,可以找到如下两条路(红色箭头和黄色箭头)

用深度优先来看前面回溯中提到的子集求法:从起点开始,首先是一个空集。往下有1、2、3三条路可以走

先逮着1开始走,1符号要求,放入结果集,接着往下走,[1,2],也符合要求,放入结果集,接着往下走,[1,2,3],也符合要求,放入结果集,再往下,就到底了。换另一条路走。
2、宽度优先搜索算法
宽度(广度)优先搜索,即BFS,和DFS不同,BFS是一层一层的处理。BFS一般搭配队列使用。

BFS和DFS的对比:

以从上到下、从左到右遍历以下二叉树为例,采用宽度优先,搭配一个队列,先进先出,计数count = 0。从root开始,root入队,count = 1,出队,同时root的左、右节点入队,并维护count。当count = 0时,说明遍历结束。

即node.val出队,node.left和node.right入队。详细:
- root节点1入队,count = 1
- 根据count,从队列中pop元素,得到root节点,把其值val放入结果集,并把其左右孩子加进来。结果集array = [1]
- 此时,队列中存着2、3这两个节点,count = 2
- 继续根据count = 2来pop两次,并加入元素的左右孩子
- pop出元素2,加入其左右节点4、5,count = 3,结果集array = [1,2]
- pop出元素3,加入其左右节点6、7,count = 4,结果集array = [1,2,3]
- pop出元素4,count = 3,array = [1,2,3,4]
- …
- pop出元素7,count = 0,array = [1,2,3,4,5,6,7]
3、leetcode102:二叉树的层序遍历
和上面分析的BFS遍历二叉树不一样,这题要求输出的结果是分层的,考虑一层一层的处理,并把每层的处理完的结果加入最终的结果集。

外层while执行一次,代表处理了二叉树的一层。内层while执行一次,代表处理这层的每个元素(自身出队、左右节点的值入队)
public class P102 {public List<List<Integer>> levelOrder(TreeNode root) {List<List<Integer>> result = new ArrayList<>();if (null == root) {return result;}Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (queue.size() > 0) {// 存每层的结果List<Integer> list = new ArrayList<>();// 每处理完一层,队列的长度,即是下一层元素的数量int count = queue.size();// 处理每一层的元素,弹出这一层的每个元素,并把每个元素的左右节点加进去while (count > 0) {TreeNode node = queue.poll();list.add(node.val);count--;// 弹出的元素的左右孩子节点的值入队if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}// 一层处理结束,把结果加到结果集里,注意别直接add上面的list,防止引用传递,用copy值传递result.add(new ArrayList<>(list));}return result;}
}
这题很明显的有”层“的概念,用BFS很合适,但DFS也能解。

从root开始,一条路往下走,和前面一层层的取不一样了,DFS解时,每层递归有个level,level = 0,即root节点所在的那层,放到结果集result的0号位置,往下9,放到result的1号元素里面
public class P102 {public List<List<Integer>> levelOrderByDfs(TreeNode root) {List<List<Integer>> result = new ArrayList<>();if (null == root) {return result;}dfs(root, result, 0);return result;}/*** 深度优先** @param node 节点* @param result 最终的结果集* @param level 二叉树中当前的层级*/public static void dfs(TreeNode node, List<List<Integer>> result, int level) {// 终止条件if (node == null) {return;}// 如果当前层级到了2,那结果集里应该初始化出两个元素,每层的结果存一个结果集的元素里if (level > result.size() - 1) {result.add(new ArrayList<>());}// 层级所在结果集的位置上,加入这个元素result.get(level).add(node.val);if (node.left != null) {dfs(node.left, result, level + 1);}if (node.right != null) {dfs(node.right, result, level + 1);}}
}
4、leetcode107:二叉树的层序遍历II

和前面102题不同的是,要求从叶子节点开始一层层的遍历,输出的顺序刚好相反,当然,可以在102的代码的末尾,直接reverse翻转答案,然后return。
说起翻转,也可自己用栈实现,但除了翻转,有更优实现:结果集result用一个链表,依旧从root节点那一层开始,从上往下一层层处理,但每层的结果,加到result的头部,如此,从上到下遍历完每层后,直接不用翻转就是题解。
Java中,List里面底层是链表的,就不能用ArrayList(数组),而是LinkedList:
public class P107 {public List<List<Integer>> levelOrderBottom(TreeNode root) {// 用链表对应的LinkedListList<List<Integer>> result = new LinkedList<>();if (null == root) {return result;}// 队列Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (queue.size() > 0) {int count = queue.size();List<Integer> levelList = new ArrayList<>();for (int i = 0; i < count; i++) {TreeNode node = queue.poll();levelList.add(node.val);if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}// 注意这里,每次add的下标是0,即链表队首,这样第二层的结果就会排到第一层result.add(0, levelList);}return result;}
}
以上实现,注意链表的巧妙之处:

这题要不用BFS,而DFS,那最后就得reverse翻转一下结果集了。虽然BFS能解的,DFS也能解,但这种层级的遍历,BFS更好用。
最后,以上用到的TreeNode:
public 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;}
}
5、leetcode938:二叉搜索树的范围和
第一反应是,遍历二叉树,判断每个元素在范围就累加。那应该想到BFS,除了BFS,还有别的实现:不管是前序、中序、后序遍历,一个树,最后肯定会被拆解成一个个只有三个节点的小块,即递归。

解法一:普通递归

从root开始,一分为二的看,最终结果 = 左 + 中 + 右,左边有子树的话,继续左 + 中 + 右,纯递归,递归终止的条件为,节点没有子节点了。代码实现:
public class P938 {public int rangeSumBST(TreeNode root, int low, int high) {if (null == root) {return 0;}// 左边那一块,新的root就是root.leftint leftSum = rangeSumBST(root.left, low, high);// 右边那一块,新的root就是root.rightint rightSum = rangeSumBST(root.right, low, high);int result = leftSum + rightSum;// 中间节点if (low <= root.val && root.val <= high) {result = result + root.val;}return result;}
}
以上面二叉树为例:
- 第一次递归:root=10, left=5,right=15
- 第二次递归:root=上一层的root.left=5,left=3,right=7
- 第三次递归:root=上一层的root.left=3,left=null,right=null
- 第四次递归:root=上一层的root.left=null,终止递归,回退,返回0
解法二:BFS
一层层的来,平铺扫荡,每一个出队的元素,判断是否在范围内,是则累加

这题的BFS,和BFS概念分析时一样,都不用像前两道题一样分层,一层while就行:
public class P938 {public int rangeSumBSTByBFS(TreeNode root, int low, int high) {if (null == root) {return 0;}int result = 0;Queue<TreeNode> queue = new LinkedList<>();queue.add(root);while (!queue.isEmpty()) {TreeNode node = queue.poll();if (node.val >= low && node.val <= high) {result = result + node.val;}// 左右节点处理if (node.left != null) {queue.add(node.left);}if (node.right != null) {queue.add(node.right);}}return result;}
}
相关文章:
【Leetcode】十六、深度优先搜索 宽度优先搜索 :二叉树的层序遍历
文章目录 1、深度优先搜索算法2、宽度优先搜索算法3、leetcode102:二叉树的层序遍历4、leetcode107:二叉树的层序遍历II5、leetcode938:二叉搜索树的范围和 1、深度优先搜索算法 深度优先搜索,即DFS,从root节点开始&a…...
Ruby教程
Ruby是一种动态的、面向对象的、解释型的脚本语言,以其简洁和易读性而闻名。Ruby的设计哲学强调程序员的生产力和代码的可读性,同时也融合了功能性和面向对象编程的特性。 以下是一个基础的Ruby教程,涵盖了一些基本概念和语法: …...
react + pro-components + ts完成单文件上传和批量上传
上传部分使用的是antd中的Upload组件,具体如下: GradingFilingReportUpload方法是后端已经做好文件流,前端只需要调用接口即可 单文件上传 <Uploadkey{upload_${record.id}}showUploadList{false}accept".xlsx"maxCount{1}customRequest{({ file }) > {const …...
暑假第一周——ZARA仿写
iOS学习 前言首页:无限轮播图商城:分类我的:自定义cell总结 前言 结束了UI的基础学习,现在综合运用开始写第一个demo,在实践中提升。 首页:无限轮播图 先给出效果: 无限轮播图,顾…...
github.com/antchfx/jsonquery基本使用
要在 GitHub 上使用 antchfx/jsonquery 库来查找 JSON 文档中的元素,首先需要了解这个库的基本用法。jsonquery 是一个用于查询 JSON 数据的 Go 语言库,允许使用 XPath 表达式来查找和选择 JSON 数据中的元素。 以下是一些基本步骤和示例,演…...
【python虚拟环境管理】【mac m3】使用poetry管理python项目
文章目录 一. 为什么选择poetry二. poetry相关操作1. 创建并激活环境2. 依赖包管理2.1. 安装项目依赖1.2. 管理不同开发环境的依赖1.3. 依赖维护1.4. 项目相关 Poetry是Python中用于依赖管理和打包的工具。它允许您声明项目所依赖的库,并将为您管理(安装…...
《JavaSE》---16.<抽象类接口Object类>
目录 前言 一、抽象类 1.1什么是抽象类 1.2抽象类代码实现 1.3 抽象类特点 1.4抽象类的作用 二、接口 2.1什么是接口 2.2接口的代码书写 2.3 接口使用 2.4 接口特点 2.5 实现多个接口 快捷键(ctrl i ): 2.6接口的好处 2.7 接…...
简单修改,让UE4/5着色器编译速度变快
简单修改,让UE4/5着色器编译速度变快 目录 简单修改,让UE4/5着色器编译速度变快 一、问题描述 二、解决方法 (一)硬件升级 (二)调整相关设置和提升优先级 1.调整相关设置 (1)…...
如何查看极狐GitLab Helm Chart?
GitLab 是一个全球知名的一体化 DevOps 平台,很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab :https://gitlab.cn/install?channelcontent&utm_sourcecsdn 是 GitLab 在中国的发行版,专门为中国程序员服务。可以一键式部署…...
代码随想录算法训练营第十六天| 530.二叉搜索树的最小绝对差、501.二叉搜索树中的众数、236. 二叉树的最近公共祖先
写代码的第十六天,自从到了二叉树错误版代码就少了,因为我自己根本没思路,都是看完思路在做,那基本上就是小语法问题,很少有其他问题了,证实了我好菜。。。。。。 还是得写思路啊啊啊啊,写思路好…...
NODEJS复习(ctfshow334-344)
NODEJS复习 web334 下载源码代码审计 发现账号密码 代码逻辑 var findUser function(name, password){ return users.find(function(item){ return name!CTFSHOW && item.username name.toUpperCase() && item.password password; }); }; 名字不等于ctf…...
【Go系列】RPC和grpc
承上启下 介绍完了Go怎么实现RESTFul api,不可避免的,今天必须得整一下rpc这个概念。rpc是什么呢,很多人都想把rpc和http一起对比,但是他们不是一个概念。RPC是一种思想,可以基于tcp,可以基于udp也可以基于…...
【VUE】v-if和v-for的优先级
v-if和v-for v-if 用来显示和隐藏元素 flag为true时,dom元素会被删除达到隐藏效果 <div class"boxIf" v-if"flag"></div>v-for用来进行遍历,可以遍历数字对象数组,会将整个元素遍历指定次数 <!-- 遍…...
【单目3D检测】smoke(1):模型方案详解
纵目发表的这篇单目3D目标检测论文不同于以往用2D预选框建立3D信息,而是采取直接回归3D信息,这种思路简单又高效,并不需要复杂的前后处理,而且是一种one stage方法,对于实际业务部署也很友好。 题目:SMOKE&…...
数据库系统概论:数据库系统的锁机制
引言 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中,数据作为一种共享资源,其并发访问的一致性和有效性是数据库必须解决的问题。锁机制通过对数据库中的数据对象(如表、行等)进行加锁,以确保在同…...
Django+vue自动化测试平台(28)-- ADB获取设备信息
概述 adb的全称为Android Debug Bridge,就是起到调试桥的作用。通过adb可以在Eclipse中通过DDMS来调试Android程序,说白了就是调试工具。 adb的工作方式比较特殊,采用监听Socket TCP 5554等端口的方式让IDE和Qemu通讯,默认情况下…...
RESTful API设计指南:构建高效、可扩展和易用的API
文章目录 引言一、RESTful API概述1.1 什么是RESTful API1.2 RESTful API的重要性 二、RESTful API的基本原则2.1 资源导向设计2.2 HTTP方法的正确使用 三、URL设计3.1 使用名词而非动词3.2 使用复数形式表示资源集合 四、请求和响应设计4.1 HTTP状态码4.2 响应格式4.2.1 响应实…...
npm下载的依赖包版本号怎么看
npm下载的依赖包版本号怎么看 版本号一般分三个部分,主版本号、次版本号、补丁版本号。 主版本号:一般依赖包发生重大更新时,主版本号才回发生变化,如Vue2.x到Vue3.x。次版本号:当依赖包中发生了一些小变化ÿ…...
css前端面试题
1.什么是css盒子模型? 盒子模型包含了元素内容(content)、内边距(padding)、边框(border)、外边距(margin)几个要素。 标准盒子模型和IE盒子模型的区别在于其对元素的w…...
Vue从零到实战
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…...
从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
Spring是如何解决Bean的循环依赖:三级缓存机制
1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间互相持有对方引用,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
LINUX 69 FTP 客服管理系统 man 5 /etc/vsftpd/vsftpd.conf
FTP 客服管理系统 实现kefu123登录,不允许匿名访问,kefu只能访问/data/kefu目录,不能查看其他目录 创建账号密码 useradd kefu echo 123|passwd -stdin kefu [rootcode caozx26420]# echo 123|passwd --stdin kefu 更改用户 kefu 的密码…...
C++:多态机制详解
目录 一. 多态的概念 1.静态多态(编译时多态) 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1).协变 2).析构函数的重写 5.override 和 final关键字 1&#…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...
MinIO Docker 部署:仅开放一个端口
MinIO Docker 部署:仅开放一个端口 在实际的服务器部署中,出于安全和管理的考虑,我们可能只能开放一个端口。MinIO 是一个高性能的对象存储服务,支持 Docker 部署,但默认情况下它需要两个端口:一个是 API 端口(用于存储和访问数据),另一个是控制台端口(用于管理界面…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
rknn toolkit2搭建和推理
安装Miniconda Miniconda - Anaconda Miniconda 选择一个 新的 版本 ,不用和RKNN的python版本保持一致 使用 ./xxx.sh进行安装 下面配置一下载源 # 清华大学源(最常用) conda config --add channels https://mirrors.tuna.tsinghua.edu.cn…...
