【数据结构】二叉树(三)精选Oj题

news2024/11/15 15:42:23

本篇已经是二叉树第三篇啦,下面讲解相关面试题,写作不易,求路过的朋友给个点赞与收藏呀~

目录

1、相同的树

2、另一颗树的子树 

 3、翻转二叉树

 4、对称二叉树

5、平衡二叉树

 6、构建二叉树

7、二叉树的最近公共祖先

孩子双亲解法

二叉搜索树解法 

普通二叉树解法    

8、二叉树创建字符串


判断两棵树是否相同、另一颗的子树、反转二叉树、判断是否为平衡二叉树、对称二叉树、二叉树的构建、最近公共祖先结点、根据前序与中序遍历构造二叉树、根据后序与中序遍历构造二叉树、二叉树创建字符串

1、相同的树

解题思路:

同时遍历两棵树

  1. 如果两棵树都是空,则相同
  2. 如果两棵树一个为空,一个不为空,则不相同
  3.  如果两棵树都不为空,先检测值是否相同,根如果相同再递归检测两棵树的左子树以及右子树是否都相同
class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        // 判断结构
        if (p == null && q == null) {
            return true;
        }
        // 判断结构       
        if (p == null || q == null) {
            return false;
        }
        // 判断值相等
        if (p.val != q.val)
            return false;
        return isSameTree(p.left, q.left) &&isSameTree(p.right, q.right);
    }
}

2、另一颗树的子树 

解题思路:

  1. 空树是任意一棵树的子树
  2. 如果两棵树相同,也可以认为是子树,因此:只要根节点相同,直接检测s和t是否为相同的树即可
  3. 如果根不相同,检测t是否为s.left的子树 或者 s.right的子树 

class Solution {

//判断subRoot是否为root子树
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if (root == null) {
            return false;
        }
//subRoot可能与root相同,可能与root.left 、root.right相同
//其中一种情况为true,则为子树
        return isSameTree(root, subRoot) || isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);
    }


//判断参数中两树是否相同
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if (p == null && q == null) {
            return true;
        } else if (p == null || q == null) {
            return false;
        } else if (p.val != q.val) {
            return false;
        } else {
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        }
    }
}

【易错点】

        return isSameTree(root, subRoot) || isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot);

(root.left, subRoot)与(root.right, subRoot)参数应传入Subtree方法中进行递归,若传入isSameTree方法中只能判断一次root的左右子树与subRoot是否相同


 3、翻转二叉树

解题思路:

二叉树前序遍历规则应用, 如果树不空时:

  1. 交换根的左右子树
  2. 递归反转根的左子树
  3. 递归反转根的右子树 
class Solution {
    public TreeNode invertTree(TreeNode root) {
    if(root==null)
    return null;

    //借助ret将root.left、root.right交换
    TreeNode ret=null;
    ret=root.left;
    root.left=root.right;
    root.right=ret;


//递归反转根的左子树
    invertTree(root.left);
//递归反转根的右子树 
     invertTree(root.right);
     return root;
    }
}

 4、对称二叉树

 

解题思路:

直接递归检测root的左右是否对称即可

  1. 如果两棵树都是空树,则对称
  2. 如果两棵树一棵为空树,一棵不为空树,则一定不是对称树
  3. 如果两棵树都不为空,先检测两棵树的root是否相同,如果相同,再检测一个的left是否为另一个的right 并且一个的right是否为另一个的left
class Solution {
    public boolean isSymmetric(TreeNode root) {
       return isSym(root.left, root.right);
    }

  //判断对称
    public boolean isSym(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 isSym(p.left,q.right)&&isSym(p.right,q.left); 
    }
}

5、平衡二叉树

平衡二叉树 是指该树所有节点的左右子树的深度相差不超过 1。

解题思路:

平衡二叉树的概念:二叉树中每个节点左右子树高度差的绝对值不能超过1 根据概念来检测:

  1. 如果是空树,直接返回,注意:空树也是平衡二叉树
  2. 求根的左右子树高度,然后做差检测其高度差的绝对值是否超过1 如果超过则不是
  3. 递归检测根的左右子树是否为平衡二叉树
class Solution {
//计算root的深度
    public int GetHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftHeight = GetHeight(root.left);
        int rightHeight = GetHeight(root.right);
//三目运算符,root深度为左右子树更大值加1
        return leftHeight > rightHeight? leftHeight+1 : rightHeight+1;
    }


//判断是否平衡
    public boolean isBalanced(TreeNode root) {
        // 空树是平衡二叉树
        if(root == null){
            return true;
        }
        // 获取root左右子树的高度
        int leftHeight = GetHeight(root.left);
        int rightHeight = GetHeight(root.right);
        // 根据平衡树的概念,检测root节点的平衡性
        if(Math.abs(rightHeight - leftHeight) >= 2){
            return false;
        }
       // 通过递归方式:检测root的左右子树是否为平衡树
        return isBalanced(root.left) && isBalanced(root.right);
    }
}
  

 6、构建二叉树

这道题偏难,可以点进牛客网链接测试,链接放这里啦

根据字符串构建二叉树

//结点类
class TreeNode {
    char val;
    TreeNode left;
    TreeNode right;
    public TreeNode(char val) {
        this.val = val;
    }
}
public class Main {
    static int i = 0;
    //创建二叉树
    public static TreeNode setUp(String str) {
        TreeNode node = null;
        //依次取出str字符串的每个字符
        char ch = str.charAt(i);
        if (ch != '#') {
            node = new TreeNode(ch);
            i++;
            node.left = setUp(str);
            node.right = setUp(str);
        } else {
            i++;
        }
        return node;
    }
    //中序遍历
    public static void inOrderTraversal(TreeNode root) {
        if (root == null)
            return;
        inOrderTraversal(root.left);
        System.out.print(root.val + " ");
        inOrderTraversal(root.right);
    }
//main方法
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            TreeNode root = setUp(str);
            inOrderTraversal(root);
        }
    }
}

 注意事项

OJ算法题分为两种类型:

  1. 接口类型OJ:此种OJ题目是方法名字已经给好,用户直接写代码即可,也不需要包含什么包
  2. IO类型的OJ:此种OJ题目需要用户定义一个public的Main类,然后在Main类中提供一个main方法,在main方法中完成事情,中间如要需要用到其他集合类,必须手动 导入包 在线OJ中的循环输入,输入单个值怎么循环接收,整行值怎么循环接收

7、二叉树的最近公共祖先

这道题有多种解法 对二叉树分情况:

孩子双亲解法

如果二叉树采用孩子双亲表示法链接,求两个节点的最近公共祖先,实际就转化为两个链表相交求交点  

二叉搜索树解法 

a. 如果树是空,直接返回null,没有最近公共祖先节点

b. 如果两个节点中有一个是根节点,最近公共祖先一定是根节点

c. 如果两个节点一个比根节点大,一个比根节点小,最近公共祖先一定是根节点

d. 如果两个节点都比根节点小,递归到根的左子树中查找

e. 如果两个节点都比根节点大,递归到根的右子树中查找        

普通二叉树解法    

 方法一:

写一个判断节点是否在二叉树中的方法,可以参考类似二叉搜索树的方法解觉

  • 如果树是空,直接返回null,没有最近公共祖先节点
  • 如果两个节点中有一个是根节点,最近公共祖先一定是根节点
  • 如果两个节点一个在根节点的左子树,一个在根节点的右子树,最近公共祖先一定是根节点
  • 如果两个节点都在左子树中,递归到左子树中找
  • 如果两个节点都在右子树中,递归到右子树中找    

方法二:受孩子双亲表示法启发,如果能够知道节点到根的路径,问题就解决了

获取节点pNode的路径,因为公共祖先从下往上找,因此将路径中的节点保存在栈中

  • 如果是空树,直接返回 
  • 将根节点入栈,如果根节点和pNode是同一个节点,该节点到根的路径找到,否则:
  • 递归在根节点的左子树中查找,如果找到,返回
  • 如果在根节点的左子树中未找到,递归到根节点的右子树中找
  • 如果右子树中没有找到,说明root一定不再路径中                 

方法三:将两个节点的路径存入栈中

  1.   在二叉树中获取两个节点的路径
  2. 如果两个路径中节点个数不一样,节点多的出栈,直到两个栈中元素相等
  • 相等时:再比较两个栈顶是不是同一个节点,
  • 如果是,最近公共祖先找到。
  • 如果不是,两个栈同时进行出栈,继续比较,直到找到为止   

下面以 普通二叉树解法 方法一举例,代码有注释哈

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {

        if (root == null)
            return null;
        if (root == p)
            return p;
        if (root == q)
            return q;

        // 找出root的左子树是否有p/q结点
        TreeNode leftTree = lowestCommonAncestor(root.left, p, q);
        // 找出root的右子树是否有p/q结点
        TreeNode rightTree = lowestCommonAncestor(root.right, p, q);

        // 若左右子树都不为空,说明找到了p、q,则最近祖先为root
        if (rightTree != null && leftTree != null)
            return root;
        // 若左子树不为空右子树为空,最近祖先为root.left
        if (leftTree != null)
            return leftTree;
        // 若左子树为空右子树不为空,最近祖先为root.right
        return rightTree;
    }
}

8、二叉树创建字符串

 解题思路: 采用二叉树前序遍历规则进行转化

  1. 如果树空,转化结束
  2. 如果树非空
  • 先转化跟节点
  • 转化根节点的左子树, 如果根的左子树非空或者左子树空但是右子树非空:( 递归转化左子树 ), 注意将转化结果内嵌到()中
  • 转化根节点的右子树 ,如果根的右子树非空:( 递归转化右子树 ), 注意将转化结果内嵌到()中
class Solution {
String str;
    public String tree2str(TreeNode t) {
        StringBuilder sb = new StringBuilder();
        tree2str(t, sb);
        return sb.toString();
    }

    public void tree2str(TreeNode t, StringBuilder str) {
        if(null == t){
            return;
        }

        // 先将根节点的数据放到str中
        str.append(t.val);

        // 处理根节点的左子树
        if(null != t.left || null != t.right)
        {

            // 左子树非空,递归转化左子树
            str.append("(");
            tree2str(t.left, str);
            str.append(")");
        }

        // 再检测t的右子树,如果右子树为空,不增加任何内容
        if(null != t.right){

            // 递归处理右子树
            str.append("(");
            tree2str(t.right, str);
            str.append(")");
        }
    }
}

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

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

相关文章

企业为何需要渗透测试

随着数字化时代的全面到来,互联网已成为企业运营不可或缺的一部分。然而,日益复杂的网络环境和不断演变的攻击手段,使得网络安全问题日益严峻。在这一背景下,渗透测试作为一种重要的安全评估手段,对于保障企业信息安全…

day24-测试之接口测试基础

目录 一、接口的定义 二、接口的优点 三、API接口 四、接口测试流程 五、网络基础概念 六、HTTP和RURL 七、get和post请求 八、数据格式 九、状态码 十、restful风格 十一、接口工具 一、接口的定义 程序之间协作所要遵循的一套规范、标准 二、接口的优点 2.1.责任…

探索和表征大型语言模型在嵌入式系统开发和调试中的应用

这篇论文的标题是《Exploring and Characterizing Large Language Models for Embedded System Development and Debugging》,作者是来自华盛顿大学的研究团队。论文主要探讨了大型语言模型(LLMs)在嵌入式系统开发和调试方面的应用潜力。以下…

前端技巧——复杂表格在html当中的实现

应用场景 有时候我们的表格比较复杂,表头可能到处割裂,我们还需要写代码去完成这个样式,所以学会在原生html处理复杂的表格还是比较重要的。 下面我们来看这一张图: 我们可以看到有些表头项的规格不太一样,有1*1 2*…

【深入理解SpringCloud微服务】Spring-Cloud-OpenFeign源码解析(下)——LoadBalancerFeignClient详解

【深入理解SpringCloud微服务】Spring-Cloud-OpenFeign源码解析(下)——LoadBalancerFeignClient详解 RxJava简单介绍RxJava示例Observable与Subscriber相关方法介绍Observable.create(OnSubscribe)Observable#just(T value)Observable#concatMap(Func1&…

实战OpenCV之图像显示

基础入门 OpenCV提供的功能非常多,图像显示是最基础也是最直观的一部分。它让我们能够直观地看到算法处理后的效果,对于调试和验证都至关重要。在OpenCV中,图像显示主要依赖于以下四个关键的数据结构和函数。 1、Mat类。这是OpenCV中最基本的…

文心快码(Baidu Comate)快速创建数据可视化图表

给你分享一个免费的编码助手——文心快码 Baidu Comate!百度文心大模型,46%采纳率,百度30%的代码都是它写的!AI这个大腿,你确定不抱一下?快来安装使用吧,送京东卡! https://dwz.cn/3…

高校疫情防控web系统pf

TOC springboot365高校疫情防控web系统pf 第1章 绪论 1.1 课题背景 互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。所以各行…

平移矩阵、点绕轴的旋转矩阵、平面直角坐标系旋转矩阵、点绕向量旋转公式(罗德里格斯旋转公式)

平移矩阵 点绕轴的旋转矩阵 平面直角坐标系旋转矩阵 点绕向量旋转公式(罗德里格斯旋转公式) 代码 #include "myPoint.h" #include <cmath> myPoint::myPoint() {m_x m_y m_z 0; }myPoint::myPoint(double x, double y, double z):m_x(x),m_y(y),m_z(z) { }…

探索tailwindcss多主题切换

现在的多主题切换基本上都是用的 css 变量的形式, 而tailwindcss也支持 css 变量定义主题的方式 至于为什么用 tailwindcss变量, 还是因为 tailwind 写类名提示比较方便, 也不需要再在css或者style中去一个个var的形式去写变量了 这里我在assets/style/theme文件夹中创建了三个…

智能与生产力、生产关系的关系

机器学习和自主系统是推动新质生产力和新质生产关系形成的关键技术。它们与这两个概念之间的关系可以从以下几个方面进行分析&#xff1a; 一、机器学习与新质生产力 提升效率和精准度&#xff1a;机器学习通过对大量数据进行分析&#xff0c;能够提供精准的预测和决策支持。这…

MyBatis(初阶)

1.什么是MyBtis MyBatis是持久层框架&#xff0c;⽤于简化JDBC的开发。 2.准备工作 2.1 创建⼯程 数据库: 2.2 配置数据库连接字符串 以application.yml⽂件为例: 2.3 写持久层代码 Data public class UserInfo {private Integer id;private String username;private Stri…

YOLOv10训练,适合小白训练,新手YOLOv10训练自己数据集教程!超简单,超详细!!

YOLOv10训练&#xff0c;适合小白训练&#xff0c;新手YOLOv10训练自己数据集教程&#xff01;超简单&#xff0c;超详细&#xff01;&#xff01; AI学术叫叫兽在这&#xff01;家人们&#xff0c;给我遥遥领先&#xff01;&#xff01;&#xff01; 方法一&#xff1a;云服务…

如何打造一款爆款手游?

现在开发一款游戏太简单了&#xff0c;各种源码满地飞&#xff0c;大家拿过来随便改改有个版号就可以上线运营了&#xff0c; 但是这种的游戏品质一般都不会怎么样&#xff0c;留存的周期也是比较短的&#xff0c;更别说让玩家持续消费了&#xff0c;想要打造一款火热的游戏我们…

Android Media Framework(十八)ACodec - Ⅵ

ACodec之所以复杂&#xff0c;主要是因为状态太多。在上一篇文章中&#xff0c;我们学习了在ExecutingState下对buffer的处理。ExecutingState可能会切换到OutputPortSettingsChangedState、FlushingState&#xff0c;或者当组件被释放时&#xff0c;进入UninitializedState。接…

泛微云桥前台文件上传漏洞-202408

漏洞简介 2024 年 8 月份新出漏洞&#xff0c;泛微云桥任意文件上传漏洞&#xff0c;详情如图所示。 环境搭建 1、下载漏洞环境。 https://wx.weaver.com.cn/download 2、运行install64.bat&#xff0c;安装环境。 3、安装成功界面。 未安装补丁&#xff0c;系统不能使用…

Java方法01:什么是方法

本节视频链接&#xff1a;Java方法01&#xff1a;什么是方法&#xff1f;_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV12J41137hu?p45&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 Java中的‌方法‌是一段执行特定任务的代码片段&#xff0c;‌它是程序的基本构…

Keepalived:不只是心跳检测,更是高可用性的秘密武器

keepalived博客(Keepalived&#xff1a;不只是心跳检测&#xff0c;更是高可用性的秘密武器) 文章目录 keepalived博客(**Keepalived&#xff1a;不只是心跳检测&#xff0c;更是高可用性的秘密武器**)keepalived介绍概述工作原理核心模块应用场景配置与安装总结 keepalived基本…

工 厂设计模式

简单工厂模式 基本介绍 1) 简单工厂模式是属于创建型模式,是工厂模式的一种。 简单工厂模式是由一个工厂对象决定创建出哪一 种产品类 的实例。简单工厂模式是工厂模式家族中最简单实用的模式 2) 简单工厂模式:定义了一个创建对象的类,由这个类来 封装实例化对象的行为 (代…

从零开始学cv-6:图像的灰度变换

文章目录 一&#xff0c;简介&#xff1a;二、图像的线性变换三、分段线性变换四&#xff0c;非线性变换4.1 对数变换4.2 Gamma变换 五&#xff0c;效果: 一&#xff0c;简介&#xff1a; 图像灰度变换涉及对图像中每个像素的灰度值执行数学运算&#xff0c;进而调整图像的视觉…