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

算法日记day 16(二叉树的广度优先遍历|反转、对称二叉树)

一、二叉树的层序遍历

题目:

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

示例 1:

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

示例 2:

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

示例 3:

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

思路:

用队列来存储元素,变量size来存储每一层的元素个数,扫描队头元素,判断其是否有左右孩子,如果有,将其入队,同时该队头元素出队,记录在该层所封装的结果集中,同时size减一,当size值减为0时,说明该层所有元素均遍历完毕,返回结果集

代码:

// 结果列表,用于存储每一层的节点值列表
public List<List<Integer>> resList = new ArrayList<List<Integer>>();// 主方法,进行二叉树的层次遍历
public List<List<Integer>> levelOrder(TreeNode root) {// 调用辅助方法进行层次遍历test(root);// 返回结果列表return resList;
}// 辅助方法,实现二叉树的层次遍历
public void test(TreeNode root) {// 如果根节点为空,直接返回if (root == null)return;// 创建队列,用于存储待处理的节点Queue<TreeNode> queue = new LinkedList<>();queue.add(root); // 将根节点加入队列// 循环处理队列中的节点,直到队列为空while (!queue.isEmpty()) {// 用于存储当前层节点值的列表List<Integer> list = new LinkedList<>();int len = queue.size(); // 当前层节点的数量// 处理当前层的所有节点while (len > 0) {TreeNode tnode = queue.poll(); // 出队列,获取当前处理的节点list.add(tnode.val); // 将节点值加入当前层的列表// 将当前节点的左右子节点加入队列,用于下一层处理if (tnode.left != null)queue.add(tnode.left);if (tnode.right != null)queue.add(tnode.right);len--; // 当前层节点数减一}// 将当前层的节点值列表加入结果列表resList.add(list);}
}
  1. resList 定义和初始化

    • public List<List<Integer>> resList = new ArrayList<List<Integer>>();
    • 定义了一个成员变量 resList,用于存储二叉树的层次遍历结果。初始化为空的 ArrayList,用于存储每一层的节点值列表。
  2. levelOrder 方法

    • public List<List<Integer>> levelOrder(TreeNode root)
    • 主方法,调用 test 方法进行二叉树的层次遍历,并返回最终的层次遍历结果 resList
  3. test 方法

    • public void test(TreeNode root)
    • 辅助方法,实现二叉树的层次遍历。
    • 使用队列 queue 进行广度优先搜索(BFS):
      • 首先将根节点加入队列。
      • 每次处理队列中的一个节点,将其值加入当前层的 list 中,并将其左右子节点(如果存在)加入队列。
      • 每处理完一层的所有节点后,将当前层的节点值列表 list 加入 resList 中。

二、翻转二叉树

题目:

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例 1:

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:

输入:root = [2,1,3]
输出:[2,3,1]

示例 3:

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

思路:

可以采用递归前序和后序遍历的方法,遍历一个结点的同时反转其左右子节点,接着往下一层移动,重复以上操作,直到遍历到的节点为空停止

代码:

//前序
public TreeNode invertTree(TreeNode root) {if (root == null)return root;swap(root); // 调用 swap 方法,交换当前节点的左右子节点  中invertTree(root.left); // 递归翻转左子树   左invertTree(root.right); // 递归翻转右子树   右return root; // 返回翻转后的根节点
}
public void swap(TreeNode root) {TreeNode temp = root.left;root.left = root.right;root.right = temp;
}

后序遍历方法类似,只需将顺序修改为左,右,中即可

用中序遍历的方法稍有不同,由于中序是左,中,右的顺序,当返回到根节点时左右子树交换顺序,此时应该继续遍历右子树,但是这时的右子树正好是刚刚交换完的左子树 ,因此实际上仅是交换了一次左子树,要想实现反转,必须再次进行左子树的交换操作即可,代码如下:

invertTree(root.left); // 递归翻转左子树   左
swap(root); // 调用 swap 方法,交换当前节点的左右子节点  中
invertTree(root.left); // 这时再次操作反转后的左子树   右

 

三、对称二叉树

题目:

给你一个二叉树的根节点 root , 检查它是否轴对称。

示例 1:

输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:

输入:root = [1,2,2,null,3,null,3]
输出:false

思路:

采用后序遍历的方法,为什么要采用后序呢?由于后序遍历的顺序是左,右,中,而要判断二叉树是否对称就是要判断根节点的左右子树是否在翻转后可以重合,后序的遍历顺序正好可以判断左右子树,再在最后遍历根节点,具体方法是,先遍历根节点的左右子节点是否相同,再判断左子节点的左子节点是否与右子节点的右子节点相同,同理再判断左子节点的右子节点是否和右子节点的左子节点相同,重复上述操作,直到为空

代码:

// 判断给定的二叉树是否对称的方法
public boolean isSymmetric(TreeNode root) {// 调用 compare 方法,比较根节点的左右子树是否对称return compare(root.left, root.right);
}// 递归比较两棵树是否对称的方法
public boolean compare(TreeNode left, TreeNode right) {// 边界情况处理:// 左子树不为空而右子树为空,或者左子树为空而右子树不为空,二叉树不对称,返回 falseif (left != null && right == null)return false;if (left == null && right != null)return false;// 左右子树都为空,认为对称,返回 trueif (left == null && right == null)return true;// 比较当前节点值是否相等,若不相等,二叉树不对称,返回 falseif (left.val != right.val)return false;// 递归比较左子树的左节点与右子树的右节点,外侧比较boolean Outcompare = compare(left.left, right.right);// 递归比较左子树的右节点与右子树的左节点,内侧比较boolean Intcompare = compare(left.right, right.left);// 返回外侧比较和内侧比较的与运算结果,确定整棵树是否对称return Outcompare && Intcompare;
}
  • 首先处理边界情况:
    • 如果 left 不为 null 而 right 为 null,或者 left 为 null 而 right 不为 null,则二叉树不对称,返回 false
    • 如果 left 和 right 都为 null,则认为是对称的,返回 true
  • 然后比较当前节点的值 left.val 和 right.val 是否相等,如果不相等,则二叉树不对称,返回 false
  • 如果当前节点值相等,继续递归比较 left 的左子节点 left.left 和 right 的右子节点 right.right 是否对称(外侧比较)。
  • 同时递归比较 left 的右子节点 left.right 和 right 的左子节点 right.left 是否对称(内侧比较)。
  • 最终返回外侧比较结果 Outcompare 和内侧比较结果 Intcompare 的与运算结果,即判断整棵树是否对称。

相关资料:

https://www.programmercarl.com/0101.%E5%AF%B9%E7%A7%B0%E4%BA%8C%E5%8F%89%E6%A0%91.html

今天的学习就到这里了! 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Android APP 基于RecyclerView框架工程(知识体系积累)
  • 在虚拟机 CentOS7 环境下安装 MySQL5.7 数据库
  • 深入理解Linux网络(三):TCP对象创建
  • [HTML]一文掌握
  • MySQL中EXPLAIN关键字详解
  • Python入门基础教程(非常详细)
  • C++ | Leetcode C++题解之第264题丑数II
  • 轨道相互作用和带隙
  • 为什么要从C语言开始编程
  • Python 热门面试题(七)
  • 十五、公开课
  • 基于SSM的网上选课系统
  • 【ACM独立出版|EI检索稳定】2024年智能感知与模式识别国际学术会议(ISPC 2024,9月6日-8)
  • Blender中的重拓扑修改器如何使用?
  • Windows系统笔记本无法连接Wi-Fi常见原因及解决办法
  • [deviceone开发]-do_Webview的基本示例
  • 3.7、@ResponseBody 和 @RestController
  • Angular 响应式表单之下拉框
  • Angularjs之国际化
  • ComponentOne 2017 V2版本正式发布
  • es6--symbol
  • HomeBrew常规使用教程
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • React 快速上手 - 06 容器组件、展示组件、操作组件
  • Redux系列x:源码分析
  • SpiderData 2019年2月16日 DApp数据排行榜
  • SpingCloudBus整合RabbitMQ
  • Spring声明式事务管理之一:五大属性分析
  • 前端代码风格自动化系列(二)之Commitlint
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 世界编程语言排行榜2008年06月(ActionScript 挺进20强)
  • 微信开放平台全网发布【失败】的几点排查方法
  • Mac 上flink的安装与启动
  • Semaphore
  • ​1:1公有云能力整体输出,腾讯云“七剑”下云端
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • ${ }的特别功能
  • (04)odoo视图操作
  • (4.10~4.16)
  • (k8s)Kubernetes本地存储接入
  • (Matalb时序预测)WOA-BP鲸鱼算法优化BP神经网络的多维时序回归预测
  • (八)Spring源码解析:Spring MVC
  • (二)windows配置JDK环境
  • (附源码)ssm智慧社区管理系统 毕业设计 101635
  • (每日一问)设计模式:设计模式的原则与分类——如何提升代码质量?
  • (三)Honghu Cloud云架构一定时调度平台
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • ***测试-HTTP方法
  • ../depcomp: line 571: exec: g++: not found
  • .NET 中 GetHashCode 的哈希值有多大概率会相同(哈希碰撞)
  • .NET 中小心嵌套等待的 Task,它可能会耗尽你线程池的现有资源,出现类似死锁的情况
  • .NET导入Excel数据
  • .NET下的多线程编程—1-线程机制概述