Java-数据结构-二叉树习题(1)

对于二叉树的学习,主要的还是得多多练习~毕竟二叉树属于新的知识,并且也并不是线性结构,再加上经常使用递归的方法解决二叉树的问题所以代码的具体流程还是无法看到的,只能通过画图+想象,所以还是必须多加练习,使自己见识的题型更多,才会熟能生巧~

第一题、相同的树

📚 思路提示

这一题还是很好想的~,对于比较两个相同的树,我们只需要像之前模拟实现二叉树的方法一样,将它拆解成 " 左子树和右子树的子问题 " 将两个树的左子树与左子树进行比较,右子树与右子树进行比较。

并且再通过递归的方式不断对子树再次执行 " 拆解成新的左子树和右子树 比较对应子树是否相同 "的操作。

直到从最底层的子树(叶子结点)递归回到两个数的根节点时,如果中途出现过 false 那么返回的就是 false ,反之则返回 true。

而其中结点的比较过程,需要判断的问题有这几种

📕 如果 p == null 并且 q == null 则代表同时达到叶子节点,返回 true 

📕 如果 p 和 q 没有进入上述判断语句,并且此时 p == null 或者 q == null 则代表有一方提前访问到了子树,则代表两棵子树的长度不相同,返回 false

📕 如果 p 和 q 都没进入上述两个判断语句,那么此时 p 和 q 都不为 null ,此时正常对它们的值进行比较,如果 p.val 不等于 q.val 则返回false

📕 最后递归函数,两次函数传参 " (p.left,q.left) && (p.right,q.right) ",只有全 true 的时候,才能最后返回 true 

图示

📖 代码示例

class Solution {public boolean isSameTree(TreeNode p, TreeNode q) {if(p == null && q == null){return true;}if(p == null || q == null || p.val != q.val){return false;}return isSameTree(p.left,q.left) && isSameTree(p.right,q.right); } 
}

第二题、另一棵树的子树

📚 思路提示

对于此题,其实就是上一题的引申~我们想要判断,一棵树是否是另一棵树的子树,那么我们首先要在另一棵树中找到这棵树的根节点

找到根节点后,我们就可以对这棵树进行判断啦~没错的,也就是判断它是否为相同的树,那么我们直接使用上一题的方法即可,首先找到根节点,然后再调用"判断是否为相同树"的方法进行递归即可

那么如何找到这个根结点呢?有以下的步骤

📕 不断递归该方法,分别传参判断(root.left)和(root.right),与subRoot的根节点是否相同(直接通过判断两棵树是否相等的方法即可)

📕 如果 root 等于 null 则返回 false 代表该子树中没找到那棵相同子树,退出递归

📕 如果"两树相同方法返回了true",则返回 true,代表该子树中找到了那棵相同子树,退出递归 

图示

📖 代码示例

class Solution {public boolean isSubtree(TreeNode root, TreeNode subRoot) {if(root == null){return false;}if(isSameTree(root,subRoot)){return true;}return isSubtree(root.left,subRoot) || isSubtree(root.right,subRoot);}public boolean isSameTree(TreeNode p, TreeNode q) {if(p == null && q == null){return true;}if(p == null || q == null || p.val != q.val){return false;}return isSameTree(p.left,q.left) && isSameTree(p.right,q.right); } 
}

第三题、翻转二叉树

想要翻转二叉树,就需要我们对树进行遍历,所以该题有多种解法,取决于它采用何种遍历。

(需要注意的是,不是将根节点下的左右子树翻转就好了,而是需要每棵树的子树都要进行翻转)

📚 思路提示[前/中/后序遍历]

还是很简单的思路,只需要不断的递归函数,再将其中的结点互换即可~这里就不再过多赘述啦~我们直接看图片

图示[前/中/后序遍历](1)

📖 代码示例(1)

    public TreeNode invertTree(TreeNode root){if(root == null){return null;}TreeNode tmp = root.left;root.left = root.right;root.right = tmp;invertTree(root.left);invertTree(root.right);return root;}

上述方法是通过借助中间变量 tmp 来实现的,接下来我们不用 tmp,而是将左右子树两个结点存储,再递归回去分别进行交换。

图示[前/中/后序遍历](2)

📖 代码示例(2)

class Solution {public TreeNode invertTree(TreeNode root) {if(root == null){return null;}TreeNode left = invertTree(root.left);TreeNode right = invertTree(root.right);root.left = right;root.right = left;return root;}
}

📚 思路提示[层序遍历]

层序遍历,在上一篇博客中我们已经讲解到了~就是将每一层的结点按照从左至右,从上至下的顺序存储到队列中,并且通过循环,将队列中的元素(一层的结点)依次出队列打印出来。

而在这题中,我们只需要在结点出队列的时候,同时将每个结点的左右子结点进行互换即可~思路还是很简单的,我们直接看图看代码~~

图示[层序遍历]

📖 代码示例(3)

class Solution {public TreeNode invertTree(TreeNode root) {if (root == null) {return null;}Deque<TreeNode> deque = new LinkedList<>();deque.push(root);while (!deque.isEmpty()) {TreeNode node = deque.removeLast();if (node.left != null) {deque.push(node.left);}if (node.right != null) {deque.push(node.right);}TreeNode tmp = node.left;node.left = node.right;node.right = tmp;}return root;}
}

第四题、反转二叉树的奇数层

我们之所以先讲了一个翻转二叉树,其实目的就是引出这道题~至于这道题应该怎么求解,其实也是换汤不换药,在这里我们提供两种解法:

📕 层序排列

📚 思路提示(1)

经过上面的那道题,相信大家对层序遍历也有了比较深刻的理解了~而对于这道题也并不难,上面的代码要求我们将所有层的左右结点都进行翻转,这题则是将奇数层的左右结点进行翻转。

所以我们只需要在循环外部定义一个变量,通过这个变量来记录每次遍历时队列中计入结点对应为第几层,再将奇数层的结点相互调换即可~

使用该方法解题有以下几点需要注意

📕 注意题中的根节点层数是以0开始的,而并非是1

📕 外层while循环不能再像上一题一样,每出队一个结点(及子树),就判断一次while循环,这样就无法获取层数

📕 而想修改上述问题,我们就需要在while循环内部再设置一个循环我们定义此时的队列元素个数为len,定义条件while(len-- > 0),并且将入队列和出队列的操作都在这个循环内部进行,这样就能解决查找层数不准确的问题了。

📕 同时,如果我们想做到上述,在一次while大循环中解决多次结点入队列出队列,那么对应的,我们也要同时应对交换结点这一步,我这里采用的方法是"当层数为奇数时,将队列中结点存入一个顺序表中,通过双指针的方法,将其中结点值进行翻转"~注意,这里不推荐使用链表,因为速度的消耗极大:

顺序表:

链表:

图示(1)

📖 代码示例(1)

class Solution {public TreeNode reverseOddLevels(TreeNode root) {if (root == null) {return null;}int num = 0;Deque<TreeNode> deque = new LinkedList<>();deque.push(root);while (!deque.isEmpty()) {int len = deque.size();if (num % 2 != 0) {List<TreeNode> list = new ArrayList<>(deque);for (int i = 0, j = list.size() - 1; i < j; i++, j--) {TreeNode tmpl = list.get(i);TreeNode tmpr = list.get(j);int tmp = tmpl.val;tmpl.val = tmpr.val;tmpr.val = tmp;}}while(len-- > 0){TreeNode node = deque.removeLast();if (node.left != null) {deque.push(node.left);}if (node.right != null) {deque.push(node.right);}}num++;}return root;}
}

📕 分解子树法

📚 思路提示(2)

这种解法相对于上一种解法就要简单许多了,同时效率也达到了显著的提升~既不用队列,也不用顺序表,更用不上循环交换节点的值!~

果然树还是得用递归呀~

其实还是很好理解的,平时我们进行结点的交换,只是传入root的左结点和右结点,就能够通过递归将所有结点都互换

那么我们只需要创建一个方法,使它的参数再多一个int类型,每次递归都在它的原基础上+1,那么就可以很清晰的分辨出是奇数层还是偶数层

至于过程也就是和平时的翻转结点多了个判断层数的步骤,这里就不再过多的画图赘述啦~我们直接看代码,包看得懂的。

📖 代码示例(2)

class Solution {public TreeNode reverseOddLevels(TreeNode root) {if (root == null) {return null;}move(root.left, root.right, 1);return root;}public void move(TreeNode left, TreeNode right, int num) {if(left == null || right == null){return;}if (num % 2 != 0) {int tmp = left.val;left.val = right.val;right.val = tmp;}move(left.left, right.right, num + 1);move(left.right, right.left, num + 1);}
}

那么这次关于二叉树的习题相关知识,就为大家分享到这里啦,作者能力有限,如果有讲得不清晰或者不正确的地方,还请大家在评论区多多指出,我也会虚心学习的!那我们下次再见哦

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

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

相关文章

PCL K4PCS算法实现点云粗配准【2025最新版】

目录 一、算法原理1、算法概述2、算法流程3、参考文献二、 代码实现1、原始版本2、2024新版三、 结果展示本文由CSDN点云侠原创,原文链接,首发于:2020年4月27日。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的抄袭狗。 博客长期更新,本文最近一次更新时间为…

09-1_信号量的理论讲解

09-1_信号量的理论讲解 信号量是操作系统中的一种同步和互斥机制&#xff0c;它通过一个计数值来表示资源的数量。通过这种方式&#xff0c;信号量可以有效地协调不同任务之间的资源使用。今天我们将深入学习信号量的基本概念、分类以及如何使用它们。 1. 信号量的基本概念 …

基于SSM汽车美容管家【提供源码+答辩PPT+文档+项目部署】(高质量源码,可定制,提供文档,免费部署到本地)

作者简介&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流。✌ 主要内容&#xff1a;&#x1f31f;Java项目、Python项目、前端项目、PHP、ASP.NET、人工智能…

Android 调用系统服务接口获取屏幕投影(需要android.uid.system)

媒体投影 借助 Android 5&#xff08;API 级别 21&#xff09;中引入的 android.media.projection API&#xff0c;您可以将设备屏幕中的内容截取为可播放、录制或投屏到其他设备&#xff08;如电视&#xff09;的媒体流。 Android 14&#xff08;API 级别 34&#xff09;引入…

SpringBoot源码解析(七):应用上下文结构体系

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;引导上下文DefaultBootstrapContext SpringBoot源码解析(三)&#xff1a;启动开始阶段 SpringBoot源码解析(四)&#xff1a;解析应用参数args Sp…

LVGL的优化

1&#xff0c;启动独立送显示线程&#xff1b; 2&#xff0c;添加主线程和display线程同步操作。 LVGL diplay单buffer&#xff1a; ----------- flush_cb()在GUI主线程渲染完成一帧后调用&#xff0c;输入变更区域&#xff0c;和变更帧数据指针: 1&#xff0c; 发送帧更新…

基于预共享密钥的IPsec实验

一、实验目的 &#xff08;1&#xff09;了解IPsec的原理和协议运行机制&#xff1b; &#xff08;2&#xff09;掌握IPsec身份认证的预共享密钥的配置&#xff1b; &#xff08;3&#xff09;掌握用Wireshark工具抓包分析IPsec数据包格式和协议流程。 二、实验设备与环境 &…

NumPy;NumPy在数据分析中的应用;NumPy与其他库的搭配使用

NumPy&#xff1b;NumPy在数据分析中的应用&#xff1b;NumPy与其他库的搭配使用 NumPy&#xff1a;Python 数据分析的核心工具什么是 NumPy&#xff1f;NumPy 的主要优势 NumPy 在数据分析中的应用1. 数据处理与清洗2. 数学和统计分析3. 数组变换与矩阵运算 NumPy 与其他库的搭…

IIO(Industrial I/O)驱动介绍

文章目录 IIO&#xff08;Industrial I/O&#xff09;驱动是Linux内核中用于工业I/O设备的子系统&#xff0c;主要用于处理传感器数据采集和转换。以下是其关键点&#xff1a; 功能 数据采集&#xff1a;从传感器读取数据。数据处理&#xff1a;对原始数据进行滤波、校准等操作…

解决关于Xcode16提交审核报错

# 问题描述 The following issues occurred while distributing your application. Asset validation failed Invalid Executable. The executable xxx.app/Frameworks/HappyDNS.framework/HappyDNS contains bitcode.(lD:ef5dd249-731f-4731-8173-8e4a12519352) Asset valida…

PenGymy论文阅读

这里发现idea被人家先发了&#xff0c;没办法&#xff0c;资料收集的不够全面&#xff0c;现在来学习一下这个项目 这篇论文的贡献如下&#xff1a; 总的来说&#xff0c;他的主要工作是构建逼真的仿真环境&#xff0c;然后根据这个仿真环境生成真实的靶场&#xff0c;使得这个…

基于Stable Diffusion 3.5 Large模型的微调技术详解

基于Stable Diffusion 3.5 Large模型的微调技术详解 引言 Stable Diffusion 3.5 Large(以下简称SD 3.5)是近年来在生成式AI领域备受关注的一个模型,尤其在图像生成任务中表现出色。它基于扩散模型(Diffusion Model)的架构,能够生成高质量的图像,并且在文本到图像(Tex…

JavaWeb 前端基础 html + CSS 快速入门 | 018

今日推荐语 指望别人的救赎&#xff0c;势必走向毁灭——波伏娃 日期 学习内容 打卡编号2025年01月17日JavaWeb 前端基础 html CSS018 前言 哈喽&#xff0c;我是菜鸟阿康。 今天 正式进入JavaWeb 的学习&#xff0c;简单学习 html CSS 这2各前端基础部分&am…

数字化时代如何甄选反垃圾邮件网关

在数字化时代&#xff0c;企业邮箱已成为企业沟通和业务运作的关键工具。然而&#xff0c;垃圾邮件的泛滥不仅干扰了正常的邮件往来&#xff0c;还可能对企业的运营造成严重影响。因此&#xff0c;企业必须采取措施&#xff0c;选择一套有效的反垃圾邮件网关来保护其邮件系统。…

从零搭建SpringBoot3+Vue3前后端分离项目基座,中小项目可用

文章目录 1. 后端项目搭建 1.1 环境准备1.2 数据表准备1.3 SpringBoot3项目创建1.4 MySql环境整合&#xff0c;使用druid连接池1.5 整合mybatis-plus 1.5.1 引入mybatis-plus1.5.2 配置代码生成器1.5.3 配置分页插件 1.6 整合swagger3&#xff08;knife4j&#xff09; 1.6.1 整…

mongodb详解二:基础操作

基础操作 数据库操作collection操作查看表插入数据查找数据 数据库操作 1.创建数据库 use test_db;如果没有数据库&#xff0c;use命令会新建一个&#xff1b;有的话&#xff0c;会切换到这个数据库 2.查看数据库 show dbs;collection操作 查看表 show tables;插入数据 …

大文件上传服务-后端V1V2

文章目录 大文件上传概述:minio分布式文件存储使用的一些技术校验MD5的逻辑 uploadV1 版本 1uploadv2 版本 2 大文件上传概述: 之前项目做了一个文件上传的功能,最近看到有面试会具体的问这个上传功能的细节&#xff0c;把之前做的项目拿过来总结一下&#xff0c;自己写的一个…

【机器学习】鲁棒(健壮)回归-Theil-Sen估计(Theil-Sen Estimator)

Theil-Sen估计 Theil-Sen估计是一种用于线性回归的非参数方法&#xff0c;其优点是对离群点具有鲁棒性。它通过计算数据点之间所有可能斜率的中位数来估计回归线的斜率&#xff0c;随后使用这些斜率估算截距。 核心思想 斜率估计&#xff1a; 对于给定的一组数据点 &#xff0…

配置Kubernetes从节点与集群Calico网络

在上一篇博客中&#xff0c;我们成功安装并初始化了Kubernetes的主节点&#xff0c;并且看到了集群初始化成功的标志信息。接下来&#xff0c;我们将继续安装从节点&#xff08;worker nodes&#xff09;&#xff0c;以构建一个完整的Kubernetes集群。 步骤回顾 在上一步中&a…

vue2:实现上下两栏布局,可拖拽改变高度

要拖拽改变两栏高度,那么总高度要确定,在拖拽的过程中,实时根据光标位置计算两栏高度,所以: 1、最外层有一个box, 高度是屏幕高度screenHeight; 2、该值在页面挂载时获取初始值(window.innerHeight-100),这里减少100,因为窗口上面有工具栏; 3、监听窗口resize事件…