数据结构:二叉树(2)

news2024/11/18 19:36:08

二叉树的基本操作

获取树的结点总数

遍历思路:

每次遍历一个节点,遍历完nodeSize++,然后遍历它的左右子树

如果遍历到空的节点,就返回0

    public int nodeSize = 0;
    int size(TreeNode root){
        if(root == null){
            return 0;
        }
        nodeSize++;
        size(root.left);
        size(root.right);
        return nodeSize;
    }

子树相加思路

整棵树的节点个数 = 左子树的节点个数+右子树的节点个数 + 根节点

    int size2(TreeNode root){
        if(root == null){
            return 0;
        }
        return size2(root.left) + size2(root.right) + 1;
    }

size2(root.left) 可以理解为左子树所有节点的总数

size2(root.right)可以理解为右子树所有节点的总数


计算二叉树叶结点的总数

遍历思路:遍历结点和左右子树,如果遍历到有一个结点左右子树都为null,那么这个结点就是叶结点,计数器++

    // 获取叶子节点的个数
    //遍历思路
    public int leafNode = 0;
    int getLeafNodeCount(TreeNode root){
        if(root == null){
            return 0;
        }
        if(root.left == null && root.right == null){
            leafNode++;
        }
        getLeafNodeCount(root.left);
        getLeafNodeCount(root.right);
        return leafNode;
    }

子树相加思路:整棵树叶子 = 左子树叶子 + 右子树叶子

    //子树相加思路
    int getLeafNodeCount2(TreeNode root) {
        if (root == null) {
            return 0;
        }
        if (root.left == null && root.right == null) {
            return 1;
        }
        return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
    }

获取第k层的结点个数

思路:

整棵树第k层节点数 = 左子树第k-1层结点数+右子树第k-1层结点数

感觉有杨辉三角的感觉(bushi

    // 获取第K层节点的个数
    public int nodeCount = 0;
    int getKLevelNodeCount(TreeNode root,int k){
        if(root == null){
            return 0;
        }
        if(k == 1){
            return 1;
        }
        return getKLevelNodeCount(root.left,k-1) + getKLevelNodeCount(root.right,k-1);
    }

 求二叉树的高度

高度就是最大层数,整棵树的高度 = 左子树的高度和右子树的高度的最大值+1

A的左子树是B,右子树是C

那B的高度怎么求呢?很简单,再递归一下呗,把B当成根结点,左子树B高度就等于B的左子树和右子树高度最大值+1

这样递归递归就能求出左子树总高度了,右子树也同理

    int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        
        return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
    }

换种写法

    int getHeight2(TreeNode root){
        if(root == null){
            return 0;
        }

        return getHeight2(root.left) > getHeight2(root.right) 
                ? getHeight2(root.left) + 1 : getHeight2(root.right) + 1;
    }

第二种写法放编译器可以跑,但是放到力扣跑不了

104. 二叉树的最大深度 - 力扣(LeetCode)

它会报这么一个错误

原因就是return的时候好不容易递归完判断左右子树大小,还得再重复递归一次计算总高度,所以跑太久力扣就给你报超时的错误了


检测特定值的元素是否存在

这个直接用前序遍历就行了

    TreeNode find(TreeNode root, int val){
        if(root == null){
            return null;
        }
        //判断根结点是不是
        if(root.val == val){
            return root;
        }
        TreeNode ret = find(root.left, val);
        if(ret != null){
            return ret;//这样就不用去右边了
        }
        TreeNode ret2 = find(root.right,val);
        if(ret2 != null){
            return ret2;
        }
        return null;
    }

二叉树面试题

100. 相同的树 - 力扣(LeetCode)

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

示例 1:

输入:p = [1,2,3], q = [1,2,3]
输出:true

示例 2:

输入:p = [1,2], q = [1,null,2]
输出:false

示例 3:

输入:p = [1,2,1], q = [1,1,2]
输出:false

提示:

  • 两棵树上的节点数目都在范围 [0, 100] 内
  • -104 <= Node.val <= 104

1.如果两个结点都不为空,就判断值

2.如果一个结点为空一个结点不为空,那必不一样

总结:判断根及其左子树和右子树是否相同

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        if((p == null && q != null)||(p != null && q == null)){
            return false;
        }
        //上面代码走完后要么两个都为空,要么都不为空
        if(p == null && q == null){
            return true;
        }
        //只剩两个都不为空的情况
        if(p.val != q.val){
            return false;
        }

        return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
    }
}


 572. 另一棵树的子树 - 力扣(LeetCode)

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

示例 1:

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

示例 2:

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出:false

提示:

  • root 树上的节点数量范围是 [1, 2000]
  • subRoot 树上的节点数量范围是 [1, 1000]
  • -104 <= root.val <= 104
  • -104 <= subRoot.val <= 104

1.注意:如果是子树,有可能是两棵相同的树,那可以先比较根结点

2.如果根结点比较完发现不是两棵相同的树,那么subRoot这棵树和root的某一棵子树是相同的

3.判断subRoot和root的左子树是不是相同的,不是就判断右子树。都不是就false了

刚刚那个isSameTree()方法不久能用上了吗

    public boolean isSameTree(TreeNode p, TreeNode q) {
        if((p == null && q != null)||(p != null && q == null)){
            return false;
        }
        //上面代码走完后要么两个都为空,要么都不为空
        if(p == null && q == null){
            return true;
        }
        //只剩两个都不为空的情况
        if(p.val != q.val){
            return false;
        }

        return isSameTree(p.left,q.left) && isSameTree(p.right,q.right);
    }
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(isSameTree(root,subRoot)){
            return true;
        }
        if(isSubtree(root.left,subRoot)){
            return true;
        }
        if(isSubtree(root.right,subRoot)){
            return true;
        }
        return false;
    }

 欸但是力扣直接给我报了一个空指针异常

这是因为假如root的左子树就是空的,root第一个if判断完之后进入左子树变成空,空指针进不了第二个if判断,所以跳过直接进入到右子树的if判断,那此时root都为空了,系统自然就报了一个空指针异常了

🆗其实我们在判断根结点是否相同前先判断会不会有空就行了

        if(root == null || subRoot == null){
            return false;
        }

 


226. 翻转二叉树 - 力扣(LeetCode)

给你一棵二叉树的根节点 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 = []
输出:[]

提示:

  • 树中节点数目范围在 [0, 100] 内
  • -100 <= Node.val <= 100

相当于我们进行数组交换一样 

每次遍历到一个结点,就把这个结点的两个引用都换一下就好了

直到所有结点都遍历完成

class Solution {
    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;
    }
}


110. 平衡二叉树 - 力扣(LeetCode)

给定一个二叉树,判断它是否是高度平衡的二叉树。

本题中,一棵高度平衡二叉树定义为:

一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。

示例 1:

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

示例 2:

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

示例 3:

输入:root = []
输出:true

提示:

  • 树中的节点数在范围 [0, 5000] 内
  • -104 <= Node.val <= 104

思路:

1.判断当前根结点的左子树高度-右子树高度的绝对值是否<=1

2.根的左子树是平衡的并且右子树也得是平衡的

这道题高度方法前面已经写完了,直接调用就行(getHeight())

class Solution {
    public int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);

        return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
    }
    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }
        //分别求左右树高度
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        //判断绝对差值<=1并且左右子树都平衡
        return Math.abs(leftHeight-rightHeight) <= 1 
        && isBalanced(root.left) && isBalanced(root.right);
    }
}

这里的时间复杂度是O(N^2),在求左子树和右子树高度调用getHeight时间复杂度已经是O(N)了,return部分再调用isBalance,相当于又遍历了一遍所有的n个结点,isBalance嵌套了getHeight,时间复杂度就是n*n了

进阶难度:使用O(N)的时间复杂度来计算

我们在求子树高度的时候,返回高度时直接让他们进行比较,如果>1就返回-1给根结点

class Solution {
    public int getHeight(TreeNode root){
        if(root == null){
            return 0;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);

        if(leftHeight >= 0 && rightHeight>=0
        && Math.abs(leftHeight - rightHeight)<=1){
          //返回真实高度
          return Math.max(leftHeight,rightHeight)+1;
        }else{
          return -1;
        }
    }
    public boolean isBalanced(TreeNode root) {
        if(root == null){
            return true;
        }
        int leftHeight = getHeight(root.left);
        int rightHeight = getHeight(root.right);
        return getHeight(root) >= 0;
    }
}

达到O(n)的时间复杂度 


101. 对称二叉树 - 力扣(LeetCode)

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

示例 1:

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

示例 2:

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

提示:

  • 树中节点数目在范围 [1, 1000] 内
  • -100 <= Node.val <= 100

 不对称:

1.一个为空另一个不为空

2.值不一样

3.左树的左和右树的左对称?左树的右和右树的左对称?

注意:left和right都为空就是对称

    public boolean isSymmetric(TreeNode root) {
        if(root == null){
          return true;
        }
        return isSymmetricChild(root.left,root.right);
    }


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

二叉树遍历_牛客题霸_牛客网 (nowcoder.com)

描述

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

输入描述:

输入包括1行字符串,长度不超过100。

输出描述:

可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。

示例1

输入:

abc##de#g##f###

输出:

c b e g d f a 

 思路:遍历这个字符串,根据前序遍历来创建二叉树,最后再用中序遍历这棵树

    public static int i = 0;
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNextLine()) { // 注意 while 处理多个 case
            String str = in.nextLine();
            TreeNode root = createTree(str);
            inorder(root);
        }
    }

    public static TreeNode createTree(String str){
        TreeNode root = null;
        //遍历字符串str
        if(str.charAt(i) != '#'){
            root = new TreeNode(str.charAt(i));
            i++;
            //根据前序遍历创建二叉树
            root.left = createTree(str);
            root.right = createTree(str);
        }else{
            i++;
        }
        //返回root之后才会继续调用createTree来创建左右子树
        return root;
    }

    public static void inorder(TreeNode root){
        if(root == null){
            return ;
        }
        inorder(root.left);
        System.out.print(root.val+" ");
        inorder(root.right);
    }

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

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

相关文章

智慧公厕:探索未来城市环境卫生设施建设新标杆

智慧公厕是当代城市建设的一项重要举措&#xff0c;它集先进技术、人性化设计和智能管理于一体&#xff0c;为人们提供更为舒适、便捷和卫生的厕所环境。现代智慧公厕的功能异常丰富&#xff0c;从厕位监测到多媒体信息交互&#xff0c;从自动化清洁到环境调控&#xff0c;每一…

电商数据平台西域根据ID取商品详情API接口采集产品详情数据、价格 、销量数据操作指南

商品详情API接口是一种用于访问和获取商品信息的接口&#xff0c;通常用于连接电商平台和商家应用程序。这个接口可以提供有关商品的各种详细信息&#xff0c;如名称、价格、描述、图片、类别、库存和评价等。它使得开发者能够为平台上的消费者提供更个性化和定制化的购物体验&…

通达OA saas化改造

登录页增加选择单位下拉菜单 <tr height"37" class"login_field"><td align"center"><b>用户名</b> <input type"text" class"text" name"UNAME" size"15" onmouseover&qu…

配电房无人值守方案

随着科技的不断进步&#xff0c;许多传统需要人工操作和维护的领域逐渐被自动化和智能化方案所替代。配电房作为电力供应的核心部分&#xff0c;也面临着同样的变革。 力安科技电易云配电室无人值守监控系统以智能物联数据采集和智能物联管控"为关键&#xff0c;通过加…

家装家具经营小程序商城的作用是什么

无论富贫&#xff0c;家里家具总是不可少的&#xff0c;也是人们生活所需&#xff0c;随着人们生活质量提升&#xff0c;市场中各式家装家具品牌也非常多&#xff0c;琳琅满目的商场里价格/质量高低可供消费者自由选择。 随着线上电商快速崛起&#xff0c;由于线上具备多品牌汇…

接口自动化测试难点:数据库验证解决方案!

接口自动化中的数据库验证&#xff1a;确保数据的一致性和准确性 接口自动化测试是现代软件开发中不可或缺的一环&#xff0c;而数据库验证则是确保接口返回数据与数据库中的数据一致性的重要步骤。本文将介绍接口自动化中的数据库验证的原理、步骤以及示例代码&#xff0c;帮…

数字电路设计得力助手——《Design Compiler User Guide》

在当今数字化时代&#xff0c;电子设备和芯片的需求日益增长&#xff0c;这使得数字电路设计变得愈发重要。在数字电路设计过程中&#xff0c;使用先进的工具和技术是至关重要的。Synopsys公司的Design Compiler就是这样一款备受推崇的设计编译器软件&#xff0c;而其详尽的用户…

Android DI框架-Hilt

到底该如何理解<依赖注入> 模版代码&#xff1a;食之无味&#xff0c;弃之可惜 public class MainActivity extends Activity {Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);TextView mTextView(TextView) findVi…

vueday01——双向绑定

1.在template里面创建一个button&#xff08;原生的不需要导入&#xff09; <button click"myclick()">数值是{{ count }}</button> 2.在setup里面声明变量和方法&#xff0c;以及将其导出 setup() {const count ref(0);const myclick () >{count.…

ROC与AUC与主动学习评价指标ALC

首先需要关注一下什么是混淆矩阵&#xff0c;此处认为1为正类&#xff0c;0为负类 预测为0预测为1真实为0TN真负例&#xff08;预测为0&#xff0c;真实也为0&#xff09;FP假正例&#xff08;预测为1&#xff0c;但真实为0&#xff09;真实为1FN假负例&#xff08;预测为0&am…

VUE 快速上手与基础指令(内附详细案例)

文章目录 前言一、vue快速上手1. vue是什么2. 创建一个vue实例3. 插值表达式4. vue的响应式特性5. 开发者工具安装 二、vue指令1. v-html2. v-if 和 v-show3. v-else 和 v-else-if4. v-on5. v-bind6. 案例-波仔的学习之旅7. v-for8. 案例-小黑的书架9. v-for 中的key10. v-mode…

Python 框架学习 Django篇 (三) 链接数据库

只要你是做后端开发的&#xff0c;那么就离不开各种数据库&#xff0c;Django框架对各种数据库都非常友好&#xff0c;比如常见的PostgreSQL、MySQL、SQLite、Oracle&#xff0c;django都对他们提供了统一调用api&#xff0c;我们这里主要使用mysql数据库作为演示 一、ORM机制 …

报考阿里云acp认证,你得到的是什么?

放眼全球能够和亚马逊AWS、微软Azure竞争的&#xff0c;国内也就只有阿里云了。 阿里云目前稳居国内云计算市场第一&#xff0c;比排后面5名同行市场占有率的总和还要多&#xff0c;全球云计算市场&#xff0c;阿里云目前排名第3位。 阿里云的市场占有率说明市场对于阿里云产…

许战海战略文库|我们的建议:华彬集团改名战马饮料集团

摘要&#xff1a;战马未能有效借势红牛,市场份额不及东鹏特饮。战马要走出当下面临的窘境,需要将华彬集团改名为战马饮料集团&#xff0c;借势红牛加强战马主品牌的认知建设构建战马饮料的产品矩阵;组建战马独立销售网络。 许战海咨询认为&#xff1a;过度差异化造成华彬集团快…

肿瘤科常用评估量表汇总,建议收藏!

根据肿瘤科医生的量表使用情况&#xff0c;笔者整理了10个肿瘤科常用量表&#xff0c;可在线评测直接出结果&#xff0c;可转发使用&#xff0c;可生成二维码使用&#xff0c;可创建项目进行数据管理&#xff0c;有需要的小伙伴赶紧收藏&#xff01; 肿瘤患者的ECOG评分标准 肿…

手机流量卡经营商城小程序的作用是什么

流量卡成为很多用户的选择&#xff0c;同时市场中也出现了不少流量卡卖家&#xff0c;基于多种形式开展生意。然而虽然市场需求度高&#xff0c;但流量卡经营难题也不少。 流量卡客户具有高忠诚度&#xff0c;然而入驻线上第三方平台&#xff0c;客户属于平台&#xff0c;无法…

檀香香料经营商城小程序的作用是什么

檀香香料有安神、驱蚊、清香等作用&#xff0c;办公室或家庭打坐等场景&#xff0c;都有较高的使用频率&#xff0c;不同香料也有不同效果&#xff0c;高品质香料檀香也一直受不少消费者欢迎。 线下流量匮乏&#xff0c;又难以实现全消费路径完善&#xff0c;线上是商家增长必…

grafana v10.1版本设置告警

1. 相关概念概述 如图所示&#xff0c;点击切换菜单标志&#xff0c;可以看到警报相关子选项。 警报规则&#xff1a;通过PromQL语句定义告警规则&#xff0c;即达到怎样的状态触发告警。 联络点&#xff1a; 设置当警报规则实例触发时&#xff0c;如何通知联系人&#xff0c;…

索引优化与查询优化(补充篇)

其他优化策略 exist和in的区别 选择的标准&#xff1a;小表驱动大表 SELECT *FROM A WHERE cc IN (SELECT cc FROM B)SELECT *FROM A WHERE EXISTS (SELECT cc FROM B WHERE B.ccA.cc)当A小于B时&#xff0c;用EXISTS。因为EXISTS的实现&#xff0c;相当于外表循环&#xff0…

猜数字游戏(Rust实现)

文章目录 游戏说明游戏效果展示游戏代码游戏代码详解生成神秘数字读取用户输入解析用户输入进行猜测比较 游戏说明 游戏说明 游戏运行逻辑如下&#xff1a; 随机生成一个1-100的数字作为神秘数字&#xff0c;并提示玩家进行猜测。如果玩家猜测的数字小于神秘数字&#xff0c;则…