【Py/Java/C++三种语言详解】LeetCode每日一题240215【二叉树BFS】LeetCode107、二叉树的层序遍历II

有LeetCode交流群/华为OD考试扣扣交流群可加:948025485
可上全网独家的 欧弟OJ系统 练习华子OD、大厂真题
绿色聊天软件戳 od1336了解算法冲刺训练

文章目录

  • 题目链接
  • 题目描述
  • 解题思路
    • DFS和BFS异同
    • 用队列维护的BFS
  • 代码
    • Python
    • Java
    • C++
    • 时空复杂度
  • 相关习题
  • 华为OD算法/大厂面试高频题算法练习冲刺训练

题目链接

LeetCode107、二叉树的层序遍历II

题目描述

给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)

示例 1

在这里插入图片描述

输入:root = [3,9,20,null,null,15,7]
输出:[[[15,7],[9,20],[3]]

示例 2

输入:root = [1]
输出:[[1]]

示例 3

输入:root = []
输出:[]

提示

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

解题思路

DFS和BFS异同

二叉树层序遍历是一个非常经典的问题,属于必须掌握的题目。

所谓二叉树遍历(traversal)指的是按照一定次序系统地访问一棵二叉树,使每个节点恰好被访问一次

二叉树遍历实质上是二叉树的线性化,将树状结构变为线性结构

二叉树遍历有两大类:

  • 深度优先(depth first traversal,DFS):先完成一棵子树的遍历再完成另一棵
  • 广度优先(breath first traversal,BFS):先完成一层节点的遍历再完成下一层

DFS和BFS均为树/图的搜索方式,能够访问树/图中的所有节点。它们的特点可以从以下的比喻看出区别:

  • DFS:优先移动节点,当对给定节点尝试过每一种可能性之后,才退到前一节点来尝试下一个位置。就像一个搜索者尽可能地深入调查未知的地域,直到遇到死胡同才回头。(下图以前序遍历为例)

在这里插入图片描述

  • BFS:优先对给定节点的下一个位置进行进行尝试,当对给定节点尝试过每一种可能性之后,才移动到下一个节点。就像一只搜索军队铺展开来覆盖领土,直到覆盖了所有地域。

在这里插入图片描述

用队列维护的BFS

树的广度优先遍历亦可称为层序遍历。其核心特点为,从上到下、从左到右访问树中的节点,每一层的节点都按顺序出现。

在这里插入图片描述

本题就是二叉树BFS的板子题,必须掌握。

BFS通常需要通过维护一个先进先出 (First In First Out,FIFO) 的队列来实现。

在这里插入图片描述

我们需要构建一个队列q用于储存每一层的所有节点,然后执行while循环(循环不变量为q不为空):

  1. 获得当前队列长度qSize,为该层的节点个数
  2. 初始化一个空的子列表subList,用于储存二叉树该层所有节点的值
  3. 执行for循环,循环qSize次。每一次循环包含以下环节
    a. 令队列q的队头节点出队,记为node,并将其值node.val存入subList
    b. 若node的左孩子node.left存在,则令node.left从队尾入队
    c. 若node的右孩子node.right存在,则令node.right从队尾入队
    (这些后入队的节点会在下一层的遍历中被取出)
  4. 经过qSize次循环后,subList已经储存了这一层节点的所有值,将subList加入全局的答案变量ans

这样就就是二叉树BFS的基本过程,其中第3步是最关键的步骤

如果题目有明显地要求区分每一层的情况(比如本题要求每一层的节点值需要单独储存在一个子列表中),则循环qSize次这个步骤是必要的。

本题沿用了LeetCode102、二叉树的层序遍历的大体框架,但最后要求返回的结果是自底向上的层序遍历,只需要返回ans数组的反转即可。即

return ans[::-1] 

代码

Python

from collections import deque
class Solution:
    def levelOrder(self, root: TreeNode) -> List[List[int]]:
        if not root:    # 若根节点为空,返回一个空列表
            return []
        ans = list()    # 初始化答案列表
        q = deque()     # 维护一个队列,用于BFS过程
        q.append(root)  # 初始化队列,加入根节点
        while(len(q) != 0):     # 循环遍历,进行BFS,退出循环的条件是队列为空
            qSize = len(q)      # 获得当前队列的长度,为二叉树该层节点数
            subList = list()    # 初始化子列表,用于储存二叉树该层节点的值
            for i in range(qSize):          # 循环qSize次,遍历该层的节点
                node = q.popleft()          # 令队头的节点node出队
                subList.append(node.val)    # 将node的值加入子列表中
                if node.left:           # 若node的左节点存在,入队
                    q.append(node.left)
                if node.right:          # 若node的右节点存在,入队
                    q.append(node.right)
            ans.append(subList) # 经过循环qSize次后,将子列表加入答案列表
        return ans[::-1]      # 退出while循环,返回答案列表

Java

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> ans = new ArrayList<>();
        if (root == null) {
            return ans;
        }

        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);

        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> subList = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                subList.add(node.val);
                if (node.left != null) {
                    queue.offer(node.left);
                }
                if (node.right != null) {
                    queue.offer(node.right);
                }
            }
            ans.add(0, subList);
        }

        return ans;
    }
}

C++

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> ans;
        if (root == nullptr) {
            return ans;
        }

        queue<TreeNode*> q;
        q.push(root);

        while (!q.empty()) {
            int size = q.size();
            vector<int> subList;
            for (int i = 0; i < size; ++i) {
                TreeNode* node = q.front();
                q.pop();
                subList.push_back(node->val);
                if (node->left != nullptr) {
                    q.push(node->left);
                }
                if (node->right != nullptr) {
                    q.push(node->right);
                }
            }
            ans.insert(ans.begin(), subList);
        }

        return ans;
    }
};

时空复杂度

时间复杂度:O(N)。仅需一次遍历整棵树。

空间复杂度:O(M)M为层的最大节点数,队列所占空间。

相关习题

LeetCode101、对称二叉树

LeetCode102、二叉树的层序遍历

LeetCode103、二叉树的锯齿形层序遍历

LeetCode107、二叉树的层序遍历II

LeetCode199、二叉树的右视图

LeetCode429、N叉树的层序遍历

LeetCode513、找树左下角的值

LeetCode515、在每个树行中找最大值

LeetCode637、二叉树的层平均值

LeetCode655、输出二叉树

LeetCode662、二叉树的最大宽度

LeetCode993、二叉树的堂兄弟节点

LeetCode1161、最大层内元素和

LeetCode1302、层数最深叶子节点的和

LeetCode1609、奇偶树


华为OD算法/大厂面试高频题算法练习冲刺训练

  • 华为OD算法/大厂面试高频题算法冲刺训练目前开始常态化报名!目前已服务100+同学成功上岸!

  • 课程讲师为全网50w+粉丝编程博主@吴师兄学算法 以及小红书头部编程博主@闭着眼睛学数理化

  • 每期人数维持在20人内,保证能够最大限度地满足到每一个同学的需求,达到和1v1同样的学习效果!

  • 60+天陪伴式学习,40+直播课时,300+动画图解视频,300+LeetCode经典题,200+华为OD真题/大厂真题,还有简历修改、模拟面试、专属HR对接将为你解锁

  • 可上全网独家的欧弟OJ系统练习华子OD、大厂真题

  • 可查看链接 大厂真题汇总 & OD真题汇总(持续更新)

  • 绿色聊天软件戳 od1336了解更多

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue2学习第一天

Vue2 学习第一天 1. 什么是 vue? Vue 是一套用于构建用户界面的渐进式框架。 2. vue 历史 vue 是在 2013 年创建的&#xff0c;vue3 是 2020 出现的&#xff0c;现在主要是用 vue2&#xff0c;创新公司用的是 vue3 vue 的作者是尤雨溪&#xff0c;vue 的搜索热度比 react…

java的面向对象编程(oop)——认识泛型

前言&#xff1a; 打好基础&#xff0c;daydayup! 泛型 1&#xff0c;认识泛型&#xff1a; 定义类&#xff0c;接口&#xff0c;方法时&#xff0c;同时声明了一个或多个类型变量&#xff08;例&#xff1a;<E>&#xff09;,称为泛型&#xff0c;泛型接口&#xff0c;泛…

计算机网络——11EMail

EMail 电子邮件&#xff08;EMail&#xff09; 3个主要组成部分 用户代理邮件服务器简单邮件传输协议&#xff1a;SMTP 用户代理 又名“邮件阅读器”撰写、编辑和阅读邮件输入和输出邮件保存在服务器上 邮件服务器 邮箱中管理和维护发送给用户的邮件输出报文队列保持待发…

###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯

前言&#xff1a;感谢您的关注哦&#xff0c;我会持续更新编程相关知识&#xff0c;愿您在这里有所收获。如果有任何问题&#xff0c;欢迎沟通交流&#xff01;期待与您在学习编程的道路上共同进步。 目录 一. 延时函数的生成 1.通过延时计算器得到延时函数 2.可赋值改变…

2月14日作业

1.请编程实现二维数组的杨慧三角 代码&#xff1a; #include <stdio.h> #include <string.h> #include <stdlib.h> int main(int argc, const char *argv[]) {int n;printf("please enter n:");scanf("%d",&n);int arr[n][n];for(…

算法——数论——快速幂

目录 快速幂 费马小定理 一、试题 算法训练 A的B的C次方次方 快速幂 快速幂是一种用于快速计算幂运算的算法。计算复杂度 O(log n)基本思想是利用指数 n 的二进制展开形式&#xff0c;将 转化为多个 a 的幂的乘积&#xff0c;然后通过迭代快速计算。 快速幂的示例代码&…

Zabbix图形中文乱码问题(显示口口)解决办法

一 切换到zabbix安装目录assets/fonts下&#xff0c;下载字体 这里使用是nginxphp作为zabbix-web展示&#xff0c;使用find 命令查找 进入目录下&#xff0c;将原有字体备份&#xff0c;下载msyh字体 wget https://www.xxshell.com/download/sh/zabbix/ttf/msyh.ttf 二 修改配…

基于FPGA的UDP实现(包含源工程文件)

1、概括 前文通过FPGA实现了ARP和ICMP协议&#xff0c;ARP协议一般用来获取目的IP地址主机的MAC地址&#xff0c;ICMP通过回显请求和回显应答来判断以太网链路是否通畅&#xff0c;这两个协议都不是用来传输用户数据的。如果用户需要向PC端传输大量数据&#xff0c;那么就必须使…

嵌入式培训机构四个月实训课程笔记(完整版)-Linux ARM驱动编程第四天-ARM Linux编程之IIC与uart (物联技术666)

链接&#xff1a;https://pan.baidu.com/s/1V0E9IHSoLbpiWJsncmFgdA?pwd1688 提取码&#xff1a;1688 教学内容&#xff1a; 1、I2C总线&#xff1a; I2C&#xff08;Inter&#xff0d;Integrated Circuit),PHILIPS公司开发的两线式半双工同步串行总线&#xff1b;可以用来连…

RCS系统之:浅谈系统设计与开发

这是我在开发RCS系统中的一些个人感悟与心得&#xff0c;写出来与大家一起分享下。是想到什么写到什么&#xff0c;如果有什么不对的&#xff0c;欢迎大家一起探讨。 有些人喜欢把WMS系统下面的系统统称为RCS系统。 但我不是这么想的&#xff0c;我这里把WMS/ERP系统与AGV之间…

AtCoder Beginner Contest 332 --- E - Lucky bag --- 题解

目录 E - Lucky bag 题目大意&#xff1a; 思路解析&#xff1a; 代码实现&#xff1a; E - Lucky bag 题目大意&#xff1a; 思路解析&#xff1a; 在方差中平均值只与输入有关为定值。看到数据范围为 2 < D < N < 15&#xff0c;想到是否能使用状压dp来进行解答…

接口测试方法论

第1章 测试那点事 单元测试》接口测试》界面测试 接口就是包含特定输入和特定输出的一套逻辑处理单元&#xff0c;用户无须知晓接口的内部实现逻辑&#xff0c;这也可以称为接口的黑河处理逻辑。因为服务对象不同&#xff0c;接口又可分为两种&#xff1a;一种是系统或服务的…

LLM Visualization可视化

可视化演示网站&#xff1a;https://bbycroft.net/llm 视频解释&#xff1a;https://www.bilibili.com/video/BV1hZ4y1E7DZ/?spm_id_from333.788&vd_sourcecc2da879c044059d9838f660bcaf4664 欢迎使用Markdown编辑器 你好&#xff01; 这是你第一次使用 Markdown编辑器 …

react【六】 React-Router 路由

文章目录 1、Router1.1 路由1.2 认识React-Router1.3 Link和NavLink1.4 Navigate1.5 Not Found页面配置1.6 路由的嵌套1.7 手动路由的跳转1.7.1 在函数式组件中使用hook1.7.2 在类组件中封装高阶组件 1.8 动态路由传递参数1.9 路由的配置文件以及懒加载 1、Router 1.1 路由 1.…

基于BitVM的乐观 BTC bridge

1. 引言 前序博客&#xff1a; 区块链互操作协议Bitcoin Bridge&#xff1a;治愈还是诅咒&#xff1f;BitVM&#xff1a;Bitcoin的链下合约 基于BitVM的乐观 BTC bridge&#xff1a; Trust-minimized two-way peg 机制 BitVM BTC bridge背后的主要思想是&#xff1a; 为比…

几个经典金融理论

完整EA&#xff1a;Nerve Knife.ex4黄金交易策略_黄金趋势ea-CSDN博客 一、预期效用理论 预期效用理论是描述人们在做出决策时如何考虑风险和不确定性的一种理论。该理论最初由经济学家冯诺伊曼&#xff08;John von Neumann&#xff09;和奥斯卡摩根斯坦恩&#xff08;Oskar…

信号量概念,使用场景,本质,接口函数(pv操作),基于环形队列的生产消费者模型(过程,三个原则,单线程,多线程)

目录 引入​​​​​​​ 介绍 概念 使用场景 引入 介绍 注意 本质 计数器的本质 [判断资源是否就绪] 和互斥锁的关联 接口函数 初始化和销毁信号量 sem_init 函数原型 sem pshared value sem_destroy pv操作 sem_wait ​编辑 sem_post 其他接口 s…

【MySQL进阶之路】MySQL 中的分库分表方案解决方案

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

话题——程序员为什么不喜欢关电脑?

程序员为什么不喜欢关电脑&#xff1f; 方向一&#xff1a;工作流程与需求 程序员的工作往往涉及长时间、连续的任务&#xff0c;如代码编写、调试、测试等。这些任务需要高度的集中和专注&#xff0c;而频繁地关机和重启可能会打断他们的工作流&#xff0c;导致他们需要重新…

猫头虎分享已解决Bug || DNS解析问题(DNS Resolution Issue):DNSLookupFailure, DNSResolveError

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …