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

【刷题】第三弹——二叉树篇(上)

文章目录

  • 一.相同的树
  • 二. 另一棵树的子树
  • 三. 翻转二叉树
  • 四. 对称二叉树
  • 五. 平衡二叉树
  • 六. 二叉搜索树
  • 七. 二叉树的遍历

一.相同的树

检查两棵树是否相同
在这里插入图片描述

思路:
1.先比较结构 结构不一样直接false
2.结构一样,在比较值

public boolean isSameTree(TreeNode p, TreeNode q) {if(p==null && q==null){ //两个都是空一样return true;}if(p!=null && q==null || p==null && q!=null){//结构不一样return false;}if(p.val!=q.val){//到这里结构一样 开始判断值return false;}return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);//递归 判断左子树和右子树}

二. 另一棵树的子树

另一颗树的子树
在这里插入图片描述
在这里插入图片描述

关于检查root和subRoot是否具有相同的结构和节点值,这个思路和我们上道题是一样的
我们可以直接使用isSameTree()函数
不过后面的递归要注意,不能再用isSameTree(),后面的递归不知是需要isSameTree(),需要的是整个subTree()
首先:判断子树和根节点是否一样? 一开始就是14 和 4 比较就没必要继续向下比较了
再者:判断子树是否和当前root的左子树一样?
最后:判断子树是否和当前root的右子树一样?

public boolean isSubtree(TreeNode root, TreeNode subRoot) {if(root==null){return false;}if(isSameTree(root,subRoot)) return true;if(isSubtree(root.left,subRoot))  return true;if(isSubtree(root.right,subRoot))  return true;return false;}public boolean isSameTree(TreeNode p, TreeNode q) {if(p==null && q==null){ //两个都是空一样return true;}if(p!=null && q==null || p==null && q!=null){//结构不一样return false;}if(p.val!=q.val){//到这里结构一样 开始判断值return false;}return isSameTree(p.left,q.left)&&isSameTree(p.right,q.right);//递归 判断左子树和右子树}

满足条件就返回true 确实是子树 所有条件都不满足,就不是子树
分析复杂度
时间复杂度:O(m*n),这里的m和n分别是主树root和子树subRoot的节点数量 最坏的情况root的每个节点都要判断才能确定是不是子树
空间复杂度:O(max(m,n)),递归的深度取决于树的高度,最坏情况下树退化为链表,递归深度为树的节点数

三. 翻转二叉树

翻转二叉树
在这里插入图片描述
在这里插入图片描述

思路:前序遍历使每一个root的左右节点都交换,临时变量tmp帮助完成交换 最后返回整颗树

正确代码:

public TreeNode invertTree(TreeNode root) {if(root==null){return null;}if(root.left==null && root.right==null){return root;//空了不用向后互换了 提升一点点效率}TreeNode tmp=root.left;root.left=root.right;root.right=tmp;invertTree(root.left);invertTree(root.right);return root;}

四. 对称二叉树

对称二叉树
在这里插入图片描述

结构不一样 肯定不是轴对称
要判断整棵树是不是轴对称 就要判断root.left 和 root,right 是不是轴对称
判断左子树和右子树结构一不一样,对应的值一不一样
1.再判断左子树的左树和右子树的右树,是否轴对称
2.左子树的右树和右子树的左树,是否轴对称

在这里插入图片描述
题目中给的函数只有一个参数,我们要左右子树一起对比才能知道对不对称,所以我们添加一个子函数,传入两个参数解决问题

//子函数
public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {if(leftTree == null && rightTree == null) {return true;}if(leftTree != null && rightTree == null || leftTree == null && rightTree != null) {return false;}if(leftTree.val != rightTree.val) {return false;}return isSymmetricChild(leftTree.left,rightTree.right)&& isSymmetricChild(leftTree.right,rightTree.left);}


完整代码:

public boolean isSymmetric(TreeNode root) {if(root==null){return true;}return isSymmetricChild(root.left,root.right);//利用子函数比较左子树右子树}public boolean isSymmetricChild(TreeNode leftTree,TreeNode rightTree) {if(leftTree == null && rightTree == null) {return true;}if(leftTree != null && rightTree == null || leftTree == null && rightTree != null) {return false;}if(leftTree.val != rightTree.val) {return false;}return isSymmetricChild(leftTree.left,rightTree.right)&& isSymmetricChild(leftTree.right,rightTree.left);}

五. 平衡二叉树

平衡二叉树
在这里插入图片描述

平衡二叉树就是每一个节点的左右子树高度差不能超过1

在这里插入图片描述

思路:使用前序遍历 遍历树的所有节点,求每个节点的左右树的高度差,h>=2,返回false &&root的左树 && root的右树 也都要是平衡的
从这里我们可以想到一个改进的点 我们这里说的是 root的左树 和root的右树也要是平衡的 我们遍历的过程中 是不是发现不平衡可以直接返回false ,这样可以大大提高时间复杂度 ,这也是字节的面试原题

我们先用第一种方法:

public boolean isBalanced(TreeNode root) {if(root==null){return true;}//我们需要求绝对值 先判断左树的高度不为负 int leftH=getHeight(root.left);int rightH=getHeight(root.right);int h=Math.abs(leftH-rightH);// if(h>=2){//     return false;// }return Math.abs(leftH-rightH)<2 && isBalanced(root.left)&&isBalanced(root.right);}//求高度public int getHeight(TreeNode root){if(root==null){return 0;}int leftHeight=getHeight(root.left);int rightHeight=getHeight(root.right);return Math.max(leftHeight,rightHeight)+1;}

这就是我们思路中说的,利用前序遍历,求每个节点的左树右树的高度差其中会有很多的重复计算高度,h<=2,&&左树平衡,&&右树平衡
分析一下时间复杂度:已经达到了O(n^2)
如果我就规定必须在时间复杂度为O(n),完成判断是否是平衡二叉树
该怎么办,其实在**&&左树平衡,&&右树平衡 的过程中,就会发生不平衡**,没必要进行到计算高度差,也就是一旦不平衡我们高度上就返回 -1 标记一下 ,后面再加上一些判断就可以不用进行后面的递归了

 public boolean isBalanced(TreeNode root) {if(root==null){return true;}//我们需要求绝对值 先判断左树的高度不为负 int leftH=getHeight(root.left);int rightH=getHeight(root.right);int h=Math.abs(leftH-rightH);// if(h>=2){//     return false;// }if(leftH<0){return false;}//左树算高度时就已经不平衡了return Math.abs(leftH-rightH)<2 && isBalanced(root.left)&&isBalanced(root.right);}//求高度public int getHeight(TreeNode root){if(root==null){return 0;}int leftHeight=getHeight(root.left);int rightHeight=getHeight(root.right);if(leftHeight<0){return -1;}if(rightHeight>=0 && Math.abs(leftHeight-rightHeight) <= 1){//保证了不会因为右树的左子树返回-1而造成的 符合高度差return Math.max(leftHeight,rightHeight)+1;}else{return -1;}}

以上就是时间复杂度为O(n)的写法
我们放到IDEA中详细解释

在这里插入图片描述
完整代码:

public boolean isBalanced(TreeNode root) {if(root==null){return true;}//我们需要求绝对值 先判断左树的高度不为负 int leftH=getHeight(root.left);int rightH=getHeight(root.right);int h=Math.abs(leftH-rightH);// if(h>=2){//     return false;// }if(leftH<0){return false;}//左树算高度时就已经不平衡了return Math.abs(leftH-rightH)<2 && isBalanced(root.left)&&isBalanced(root.right);}//求高度public int getHeight(TreeNode root){if(root==null){return 0;}int leftHeight=getHeight(root.left);int rightHeight=getHeight(root.right);if(leftHeight<0){return -1; //}if(rightHeight>=0 && Math.abs(leftHeight-rightHeight) <= 1){ //保证了不会因为右树的左子树返回-1而造成的 符合高度差return Math.max(leftHeight,rightHeight)+1;}else{return -1;}}

六. 二叉搜索树

二叉搜索树与双向链表

二叉搜索树:二叉树的左子树每个节点都比根小, 右子树每个节点都比根大
所以转化成双向链表要使用中序遍历

思路:要中序遍历 改变每个节点的前驱后继 一直遍历到头结点的前驱为空(左树),那就是链表的头

public TreeNode Convert(TreeNode pRootOfTree) {if(pRootOfTree==null){return null;}ConvertChild(pRootOfTree);TreeNode head=pRootOfTree;while(head.left!=null){head=head.left;}return head;}TreeNode prev=null;public void  ConvertChild(TreeNode root){if(root==null){return ;}ConvertChild(root.left);root.left=prev;if(prev!=null){prev.right=root;}prev=root;ConvertChild(root.right);}

在这里插入图片描述

七. 二叉树的遍历

二叉树的遍历
在这里插入图片描述

首先创建一个二叉树,只用前序遍历能创建吗?–不可以
必须使用两种遍历才能创建一个二叉树
前序遍历和后序遍历可以确定一颗二叉树吗?–不可以
前序和后序都是确定的根,光知道根不可能确定一颗二叉树
所以确定二叉树时必须有中序遍历来确定左子树和右子树

但是这道题,只需要前序遍历是可以确定一颗二叉树的
为什么,不是说要两种遍历一起吗?
题目中已经告诉了我们他一定是前序遍历,并且说明了空树的位置,就能确定唯一的二叉树了

在这里插入图片描述

charAt()返回值为char字符类型
一个文件中只能有一个public修饰的类
静态类中不能使用非静态变量

class TreeNode{ //一个文件只能有一个public修饰的类public char val;public TreeNode left;public TreeNode right;public TreeNode(char val){this.val=val;}
}// 注意类名必须为 Main, 不要有任何 package xxx 信息
public class Main {public static void main(String[] args) {Scanner in = new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseString str=in.nextLine();//接收用户输入//利用前序遍历 创建树TreeNode root=creatTree(str);inorderTree(root);}}
public static int i=0;public static TreeNode creatTree(String str){TreeNode root=null;if(str.charAt(i)!='#'){root=new TreeNode(str.charAt(i));i++;root.left=creatTree(str);root.right=creatTree(str);}else{i++;}return root;}//中序遍历public static void inorderTree(TreeNode root){if(root==null){return ;}inorderTree(root.left);System.out.print(root.val+" ");inorderTree(root.right);}

在这里插入图片描述

在这里插入图片描述

相关文章:

  • 【C++ 真题】P3456 [POI2007] GRZ-Ridges and Valleys
  • AI大模型从0到1记录学习 数据结构和算法 day20
  • 【Linux】网络基础和socket(4)
  • SQL进阶知识:六、动态SQL
  • 济南国网数字化培训班学习笔记-第二组-5节-输电线路设计
  • 解决 PostgreSQL 检查约束导致的数据插入异常问题
  • 网络IP冲突的成因与解决方案
  • 三维重建模块VR,3DCursor,MPR与VR的坐标转换
  • 二叉树的创建,增加,前序遍历
  • Bytebase 取得 SOC 2 Type 1 认证
  • 第55讲:农业人工智能的跨学科融合与社会影响——构建更加可持续、包容的农业社会
  • YOLOv5改进(十)-- 轻量化模型MobileNetv4
  • Sharding-JDBC 系列专题 - 第十篇:ShardingSphere 生态与未来趋势
  • PHYBench:首个大规模物理场景下的复杂推理能力评估基准
  • C++23文本编码革新:迈向更现代的字符处理
  • 2025年3月电子学会青少年机器人技术(五级)等级考试试卷-理论综合
  • 10.接口而非实现编程
  • CentOS 7上Memcached的安装、配置及高可用架构搭建
  • LLM学习笔记4——本地部署Docker、vLLM和Qwen2.5-32B-Instruct实现OpenManus的使用
  • Qt 中线程使用
  • 神舟二十号3名航天员顺利进驻中国空间站
  • 《哪吒之魔童降世》电影版权方诉《仙侠神域》游戏运营方侵权案开庭
  • “两高”发布侵犯知产犯罪司法解释:降低部分犯罪入罪门槛
  • 东部战区新闻发言人就美“劳伦斯”号导弹驱逐舰过航台湾海峡发表谈话
  • 魔都眼·上海车展②|小鹏汽车:何小鹏携手机器人车模首秀
  • 中国围棋协会将不组队参加今年的LG杯世界棋王赛