【代码随想录训练营】【Day15】第六章|二叉树|层序遍历|226.翻转二叉树|101.对称二叉树

news2024/10/2 10:25:50

层序遍历

题目详细:LeetCode.102

层序遍历与上一节讲的三种遍历方式有所不同,层序遍历是指按从上到下,从左到右的顺序,逐层地遍历二叉树的节点。

从其节点的遍历顺序上观察,我们可以发现其跟广度优先遍历(BFS)的遍历思想非常相似,既然我们可以利用队列先进先出的特点来实现广度优先遍历,那么我们也可以用队列来实现对二叉树的层序遍历:

  • 定义一个二维数组,其下标表示第i层,数组元素则存储着每一层遍历的节点
  • 定义一个队列,利用其先进先出的特点,先将非空的根节点进队
  • 定义一个循环,遍历入队的二叉树节点
    • 定义一个变量,记录每一层的节点数目,也就是当前队列的长度
    • 定义一个循环,获取变量得知在第一层,只有根节点一个节点
      • 那么我们只需要出队一次,将根节点出队,队列长度 - 1
      • 定义一个一维数组存放该层的节点值,并将该数组追加入到二维数组中
      • 然后将其非空的左右节点依次进队
      • 循环直到该层的节点都遍历完毕
  • 循环直到队列为空,说明二叉树层序遍历完成

Java解法(队列,BFS):

class Solution {
    public List<List<Integer>> ans = new ArrayList<>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        this.bfs(root);
        return ans;
    }

    public void bfs(TreeNode root){
        Queue<TreeNode> queue = new LinkedList<>();
        if(null != root) queue.offer(root);
        while(!queue.isEmpty()){
            int n = queue.size();
            List<Integer> floor = new ArrayList<>();
            while(n-- > 0){
                TreeNode node = queue.poll();
                floor.add(node.val);
                if(null != node.left) queue.offer(node.left);
                if(null != node.right) queue.offer(node.right);
            }
            ans.add(floor);
        }
    }
}

这道题我们可以模拟层序遍历的思想,利用递归来解题,只需要在递归函数中增加一个变量,记录节点是第几层的即可:

Java解法(模拟,递归):

class Solution {
    public List<List<Integer>> ans = new ArrayList<>();

    public List<List<Integer>> levelOrder(TreeNode root) {
        this.order(root, 0);
        return ans;
    }

    public void order(TreeNode root, int level){
        if(null == root) return;
        if(level > ans.size() - 1){
            List<Integer> floor = new ArrayList<>();
            floor.add(root.val);
            ans.add(floor);
        }else{
            ans.get(level).add(root.val);
        }
        this.order(root.left, level + 1); 
        this.order(root.right, level + 1); 
    }
}

学会了二叉树的层序遍历后,可以一口气打完以下十道LeetCode题:

102.二叉树的层序遍历
104.二叉树的最大深度
107.二叉树的层次遍历II
111.二叉树的最小深度
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针II
199.二叉树的右视图
429.N叉树的层序遍历
515.在每个树行中找最大值
637.二叉树的层平均值


翻转二叉树

题目详细:LeetCode.226

翻转二叉树的过程和结果:
在这里插入图片描述
观察上图动画我们可以发现,上图采用的是层序遍历的顺序,在遍历的过程中,将每个节点的左右节点进行交换,这就是翻转二叉树的解题思想。

所以想要解题很简单,就是采用合适的遍历方法,在访问节点的时候,将其左右节点进行交换即可;

需要注意的是,在这道题中我们采用的遍历二叉树方法一般是:前序遍历、后序遍历和层序遍历,因为采用中序遍历的方式会导致重复交换子节点,需要在遍历过程中加以逻辑判断才能避免这一情况,不易编写和理解。

如何遍历在这里就不作赘述了,不了解的可以查看上一节的内容,详细讲述了遍历二叉树的各种方法:【Day14】传送门

Java解题(递归,前序遍历):

class Solution {
    public TreeNode invertTree(TreeNode root) {
        this.invertPre(root);
        return root;
    }

    public void swapChildNode(TreeNode node){
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
    }

    public void invertPre(TreeNode root){
        if(null == root) return;
        this.swapChildNode(root);
        this.invertPre(root.left);
        this.invertPre(root.right);
    }
}

Java解题(统一迭代,前序遍历):

class Solution {
    public TreeNode invertTree(TreeNode root) {
        this.invertPre(root);
        return root;
    }

    public void swapChildNode(TreeNode node){
        TreeNode temp = node.left;
        node.left = node.right;
        node.right = temp;
    }

    public void invertPre(TreeNode root){
        Stack<TreeNode> stack = new Stack<>();
        if(null != root) stack.push(root);
        while(!stack.isEmpty()){
        	// 标记节点
            TreeNode tagNode = stack.peek();
            if(tagNode != null){
            	// 非标记节点,先弹出,在需要处理的节点后追加空指针作为标记(仅作标记,不作处理)
                TreeNode node = stack.pop();
                if(null != node.right) stack.push(node.right);
                if(null != node.left) stack.push(node.left);
                stack.push(node);
                stack.push(null);
            }else{
            	// 遇到标记节点,先弹出作为标记的空指针的节点,再处理数据(处理节点,不作标记)
                stack.pop();
                TreeNode node = stack.pop();
                this.swapChildNode(node);
            }
        }
    }
}

对称二叉树

题目详细:LeetCode.101

由题可知,判断一棵二叉树是否对称:

  • 根节点无需比较
  • 接着比较树的内侧的节点和外侧的节点,而不是比较树的左右节点
  • 当每棵子树都满足内侧节点相等,外侧节点相等,那么则称这整棵二叉树是对称的

所以关键在于如何遍历二叉树,以及如何比较树的内侧节点和外侧节点。

既然根节点不需要比较,那么我们就需要同时比较其左右两棵子树上的节点,在比较过程中,会出现四种情况:

  • 左右节点皆为空,则是对称的
  • 左右节点只有一个为空,则是不对称的
  • 左右节点皆不为空,但是他们的值不相等,是不对称的
  • 左右节点皆不为空,但是他们的值相等,是对称的

所以对于每一棵子树,我们只需要按照上述情况去比较其内侧和外侧节点,就可以得到正确答案:

  • 树的内侧节点左子树的右节点和右子树的左节点进行比较
  • 树的外侧节点左子树的左节点和右子树的右节点进行比较
  • 当出现一种不对称情况时,则整个树是不对称的,无需继续比较
  • 当出现对称情况时,继续比较剩余的左右子树

Java解题(递归):

class Solution {
    public boolean isSymmetric(TreeNode root) {
        return this.check(root.left, root.right);
    }

    public boolean check(TreeNode leftNode, TreeNode rightNode){
        if(null == leftNode && null == rightNode) 
            return true;
        else if(null == leftNode || null == rightNode || leftNode.val != rightNode.val) 
            return false;
        return check(leftNode.right, rightNode.left) && check(leftNode.left, rightNode.right);
    }
}

Java解题(迭代,队列):

class Solution {
    public Queue<TreeNode> queue = new LinkedList<>();

    public boolean isSymmetric(TreeNode root) {
        return this.check(root.left, root.right);
    }

    public boolean check(TreeNode leftNode, TreeNode rightNode){
        this.queue.offer(leftNode);
        this.queue.offer(rightNode);
        while(!queue.isEmpty()){
            leftNode = queue.poll();
            rightNode = queue.poll();
            if(null == leftNode && null == rightNode)
                continue;
            else if(null == leftNode || null == rightNode || leftNode.val != rightNode.val){
                return false;        
            this.queue.offer(leftNode.right);
            this.queue.offer(rightNode.left);
            this.queue.offer(leftNode.left);
            this.queue.offer(rightNode.right);
        }
        return true;
    }
}

观察代码以及二叉树的遍历过程,我们也可以发现,对于对称二叉树的遍历顺序,左子树的遍历顺序是右左根,而右子树的遍历顺序是左右根,两者都属于后序遍历,也就是说,这道题是基于后序遍历来解决的。


除了在二叉树中常用的递归方法外,我们还可以结合前面学习的其他数据结构,如栈和队列,也能够辅助我们遍历和处理二叉树。

最后这两天做二叉树相关的题目之后,给我的感触就是,二叉树的题目千变万化,但是总结起来就是两个要点:选择最佳的遍历顺序 + 处理节点的需求逻辑,可见解答二叉树相关的题目时,理解和掌握二叉树不同的遍历思想是尤其重要的:

水之积也不厚,则其负大舟也无力。

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

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

相关文章

分布式事务理论基础

事务是数据库执行过程中的一个逻辑单位&#xff0c;由一个有限的数据库操作序列构成。 事务有四个特性&#xff0c;习惯上被称为 ACID 特性&#xff1a; Atomicity(原子性) Consistency(一致性) Isolation(隔离性) Durability(持久性) 本地事物 在系统发展初期&#xff0c…

17.微服务SpringCloud

一、基本概念 Spring Cloud 被称为构建分布式微服务系统的“全家桶”&#xff0c;它并不是某一门技术&#xff0c;而是一系列微服务解决方案或框架的有序集合。它将市面上成熟的、经过验证的微服务框架整合起来&#xff0c;并通过 Spring Boot 的思想进行再封装&#xff0c;屏蔽…

Composer: Unknown package has no name defined

安装chatGPT插件到项目&#xff0c;发现如下提示&#xff0c;更新也是提示&#xff1a; Unknown package has no name defined 目录 问题表现 解决未定义包装库 查看当前项目配置 重装本地类库 1.删除相关文件夹及文件 2.清除缓存 3.执行composer install 问题表现 执行…

SQL中的游标、异常处理、存储函数及总结

目录 一.游标 格式 操作 演示 二.异常处理—handler句柄 格式 演示 三.存储函数 格式 参数说明 演示 四.存储过程总结 一.游标 游标(cursor)是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括游标的声明、OPEN、…

ThingsBoard-规则链-check relation

1、概述 今天我主要讲解【check relation】规则节点,顾名思义,这个节点就是检查消息的发起者与其他实体之间的关系是否存在。如果勾了“检查与特定实体的关系”,则必须指定相关实体。否则,规则节点检查是否存在与匹配方向和关系类型标准的任何实体的关系。一般情况,我们都…

C++递归算法回溯思想

文章目录一、最简单的递归问题&#xff08;调用函数后无其他代码、不涉及复杂的回溯思想&#xff09;二、递归函数中的return不是结束整个递归函数哦三、递归(涉及回溯)举例学生的年龄问题&#xff08;递归的执行过程&#xff09;四、涉及较复杂的回溯思想楼梯问题一、最简单的…

Zookeeper (更新中)

目录Zookeeper 概述Zookeeper 的特点Zookeeper 的应用场景Zookeeper的数据结构ZNode数据类型ZNode里面存储的信息Zookeeper的选举机制&#xff08;重要&#xff09;Zookeeper第一次启动选举机制Zookeeper非第一次启动选举机制Zookeeper 底层如何按照请求的先后顺序来处理的Zook…

计算机SCI期刊审稿人,一般关注论文的那些问题? - 易智编译EaseEditing

编辑主要关心&#xff1a; &#xff08;1&#xff09;文章内容是否具有足够的创新性&#xff1f; &#xff08;2&#xff09;文章主题是否符合期刊的受众读者&#xff1f; &#xff08;3&#xff09;文章方法学是否合理&#xff0c;数据处理是否充分&#xff1f; &#xff08;…

3|射频识别技术|第五讲:数据通信和编码技术|第九章:编码与调制|重点理解掌握传输介质中的有线传输介质

计算机网络部分&#xff1a;https://blog.csdn.net/m0_57656758/article/details/128943949传输介质分为有线传输介质和无线传输介质两大类&#xff1b;有线传输介质通常包含双绞线、同轴电缆和光导纤维&#xff1b;无线传输介质包含微波、红外线等。传输介质的选择和连接是网络…

02Hadoop环境搭建

版本 hadoop-3.1.3.tar.gz解压安装文件到/opt/module下面 [sarahhadoop102 software]$ tar -zxvf hadoop-3.1.3.tar.gz -C /opt/module/将Hadoop添加到环境变量 &#xff08;1&#xff09;获取Hadoop安装路径 [sarahhadoop102 hadoop-3.1.3]$ pwd /opt/module/hadoop-3.1.3&…

Toolformer: Language Models Can Teach Themselves to Use Tools

展示了LM可以通过简单的API教自己使用外部工具&#xff0c;并实现两个世界的最佳效果。我们介绍了Toolformer&#xff0c;这是一个经过训练的模型&#xff0c;可以决定调用哪些API&#xff0c;何时调用&#xff0c;传递哪些参数&#xff0c;以及如何将结果最好地纳入未来的标记…

Spring Cloud Alibaba环境搭建

环境依赖 SpringCloud Alibaba 依赖 Java环境来运行。还需要为此配置 Maven环境&#xff0c;请确保是在以下版本环境中安装使用: 1. 64 bit JDK 1.8&#xff1b;下载& 配置。 1.8.0_131 2. Maven 3.2.x&#xff1b;下载& 配置搭建微服务 1.建立微服务项目 1.idea通过…

yolov5编译安卓APP:解决图像上全是检测框

yolov5编译安卓APP&#xff1a;解决图像上全是检测框前言一、第一个YOLOv5 APP1.参考链接2.详细说明3.APP检测时图像上全是框的解决方法二、第二个YOLOv5 APP1.参考链接2.详细说明3.APP检测时图像上全是框的解决方法三、其他1.APK打包2.修改APP图标与名字前言 YOLOv5编译安卓A…

【精选论文 | Capon算法与MUSIC算法性能的比较与分析】

本文编辑&#xff1a;调皮哥的小助理 【正文】 首先说结论&#xff1a; 当信噪比&#xff08;SNR&#xff09;足够大时&#xff0c;Capon算法和MUSIC算法的空间谱非常相似&#xff0c;因此在SNR比较大时它们的性能几乎一样&#xff0c;当不同信号源的入射角度比较接近时&…

蓝桥杯刷题024——天干地支

2020国赛 题目描述 古代中国使用天干地支来记录当前的年份。 天干一共有十个&#xff0c;分别为&#xff1a;甲&#xff08;jiǎ&#xff09;、乙&#xff08;yǐ&#xff09;、丙&#xff08;bǐng&#xff09;、丁&#xff08;dīng&#xff09;、戊&#xff08;w&#xff09…

IO知识整理

IO 面向系统IO page cache 程序虚拟内存到物理内存的转换依靠cpu中的mmu映射 物理内存以page&#xff08;4k&#xff09;为单位做分配 多个程序访问磁盘上同一个文件&#xff0c;步骤 kernel将文件内容加载到pagecache多个程序读取同一份文件指向的同一个pagecache多个程…

MySQL(五)

通过索引进行优化 索引基本知识 索引的优点 1、大大减少了服务器需要扫描的数据量2、帮助服务器避免排序和临时表3、将随机io变成顺序io 索引的用处 1、快速查找匹配WHERE子句的行2、从consideration中消除行,如果可以在多个索引之间进行选择&#xff0c;mysql通常会使用找到…

【Python爬虫案例教学】采集某网站壁纸,实现壁纸自由

前言 (&#xff61;&#xff65;∀&#xff65;)&#xff89;&#xff9e;嗨 大家好&#xff0c;这里是小圆 现在开始每天都给大家 分享些关于python爬虫的案例教学 从最简单的开始 — 采集图片壁纸 今天就来扒拉这个优质的壁纸网站~ 网址 &#x1f447; 顺便瞧一眼 这里的…

30 - 面向对象的其他语法

目录 一、本章重点 二、对象的分类 1、类对象 &#xff08;1&#xff09;理解 &#xff08;2&#xff09;作用 2、实例对象 &#xff08;1&#xff09;理解 三、属性的划分 1、实例属性 &#xff08;1&#xff09;概念 &#xff08;2&#xff09;定义 &#xff08;3&#xff09…

操作系统的概念,功能和目标

一、概念&#xff1a; 操作系统是指①控制和管理整个计算机系统的硬件和软件资源&#xff0c;并合理地组织调度计算机的工作和资源的分配&#xff0c;以②提供给用户和其他软件方便的接口和环境&#xff0c;它③是计算机系统中最基本的系统软件。 二、功能和目标&#xff1a;…