代码随想录:二叉树11-12

目录

222.完全二叉树的节点个数

题目

代码(层序迭代)

代码(后序递归)

代码(满二次树递归)

总结

110.平衡二叉树

题目

代码(后序递归)

代码(层序迭代)

代码(前序迭代)

总结


222.完全二叉树的节点个数

题目

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例 1:

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

代码(层序迭代)

class Solution {
    public int countNodes(TreeNode root) {

        //用层序迭代递归计算
        int size = 0; //初始大小为0
        Queue<TreeNode> que = new ArrayDeque<>();

        if(root == null){
            return 0;
        }

        que.offer(root);

        while(!que.isEmpty()){
            int len = que.size();  //获取当前层的节点个数
            size += len;  //更新size
            //当前层节点一个个出队
            while(len-- > 0){
                TreeNode cur = que.poll();
                //处理左右孩子,进队
                if(cur.left != null){
                    que.offer(cur.left);
                }
                if(cur.right != null){
                    que.offer(cur.right);
                }
            }
        }
        return size;
        

    }
}

代码(后序递归)

class Solution {
    public int countNodes(TreeNode root) {
        //用后序递归遍历计算
        //终止条件
        if(root == null){
            return 0;
        }
        //单层逻辑
        int left = countNodes(root.left); //计算左子树节点数量(左)
        int right = countNodes(root.right); //计算右子树节点数量(右)
        int result = left + right + 1; //中
        return result;

    }
}

代码(满二次树递归最难理解)

class Solution {
    //用完全二叉树的性质递归计算,时间复杂度小于o(n)
    //核心原理是如果是满二叉树,左右侧深度一样,可以2^depth-1直接计算,不用全部遍历
    public int countNodes(TreeNode root) {
        //终止条件1
        if(root == null){
            return 0;
        }
        //终止条件2,是满二叉树,可以直接根据深度计算节点数
        TreeNode left = root.left;
        TreeNode right = root.right;
        int leftdepth = 0;
        int rightdepth = 0;
        //左孩子一直往左下走,计算左下深度
        while(left != null){
            left = left.left;
            leftdepth++;
        }
        //右孩子一直往右下走,计算右下深度
        while(right != null){
            right = right.right;
            rightdepth++;
        }
        //如果左右深度一样,说明是满二叉树,直接计算返回
        if(leftdepth == rightdepth){
            //按注释计算2^depth-1 力扣上不知道为什么通不过
            //return ((int)Math.pow(2,leftdepth) - 1);
            return (2 << leftdepth) - 1;
        }

        //单层逻辑
        int l = countNodes(root.left); //计算左孩子节点数(左)
        int r = countNodes(root.right); //计算右孩子节点数(右)
        int result = l + r + 1; //中
        return result;
    }
}

总结

        层序迭代和后序递归的核心逻辑很简单,就是用普通的遍历二叉树的方法,一边遍历一边计算节点数,即在原先的遍历代码中加上计算节点数的代码即可。时间复杂度是o(n)。

        满二叉树递归的核心逻辑,利用了满二叉树的性质,如果一个子树的满二叉树,从根节点往左和往右的最大深度是一样的。因此我们通过前序递归遍历二叉树,如果当前节点时满二叉树(终止条件),就可以直接计算节点数是2^depth-1,不用继续遍历其孩子节点。如果不是满二叉树(单层逻辑),就继续前序遍历下去,不是满二叉树的节点数=左子树节点+右子树节点+1。时间复杂度<=o(n)。

110.平衡二叉树

题目

给定一个二叉树,判断它是否是平衡二叉树

示例 1:

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

代码(后序递归最难理解)

class Solution {
    //后序递归判断
    public boolean isBalanced(TreeNode root) {
        int result = postOrder(root);
        if(result == -1){
            return false;
        }
        else{
            return true;
        }

    }
    //后序遍历,判断每个节点是否满足高度差<=1
    //返回值int有两层意思:如果=-1代表当前节点不平衡,如果不是-1,代表当前节点的高度
    public int postOrder(TreeNode root){
        //终止条件1
        if(root == null){
            return 0;
        }
        //计算当前节点的左右孩子高度
        int leftheight = postOrder(root.left); //左子树高度
        int rightheight = postOrder(root.right); //右子树高度
        //终止条件2,左子树不平衡
        if(leftheight == -1){
            return -1;
        }
        //终止条件3,右子树不平衡
        if(rightheight == -1){
            return -1;
        }
        //终止条件4,左右子树高度差大于1
        if(Math.abs(leftheight - rightheight) > 1){
            return -1;
        }
        //单层循环
        //如果该节点满足平衡二叉条件,计算该节点的高度,继续递归判断
        int result = 1 + Math.max(leftheight,rightheight);
        return result;

    }
}

代码(层序迭代)

class Solution {
    //层序迭代判断,核心逻辑是层序遍历每个节点,判断是否满足平衡条件
    public boolean isBalanced(TreeNode root) {
        //层序遍历节点,逐个判断该节点是否满足高度差<=1
        Queue<TreeNode> que = new ArrayDeque<>();

        if(root == null){
            return true;
        }

        que.offer(root);

        while(!que.isEmpty()){
            int size = que.size();
            //处理当前层的所有节点
            while(size-- > 0){
                TreeNode cur = que.poll();
                //计算cur的左右孩子的高度
                int leftheight = getheight(cur.left);
                int rightheight = getheight(cur.right);
                //如果高度差>1,不满足平衡直接return
                if(Math.abs(leftheight - rightheight) > 1){
                    return false;
                }
                if(cur.left != null){
                    que.offer(cur.left);
                }
                if(cur.right != null){
                    que.offer(cur.right);
                }
            }
        }
        return true;
    }
    //计算cur节点的高度
    public int getheight(TreeNode cur){
        //终止条件
        if(cur == null){
            return 0;
        }
        //单层逻辑
        int left = getheight(cur.left);
        int right = getheight(cur.right);
        return 1 + Math.max(left,right);
    }
}

代码(前序迭代)

class Solution {
    
    public boolean isBalanced(TreeNode root) {
        Stack<TreeNode> stack = new Stack<>();
        if(root == null){
            return true;
        }
        //前序迭代遍历每一个节点,并判断该节点是否平衡
        stack.push(root);
        while(!stack.isEmpty()){
            TreeNode cur = stack.pop();
            //计算当前cur节点的左右高度
            int leftheight = getheight(cur.left);
            int rightheight = getheight(cur.right);
            //如果cur不平衡,直接返回false
            if(Math.abs(leftheight - rightheight) > 1){
                return false;
            }
            if(cur.right != null){
                stack.push(cur.right);
            }
            if(cur.left != null){
                stack.push(cur.left);
            }
        }
        //遍历完全部节点,都满足平衡,就返回true
        return true;
        
    }
    
    //计算cur节点的高度
    public int getheight(TreeNode cur){
        //终止条件
        if(cur == null){
            return 0;
        }
        //单层逻辑
        int left = getheight(cur.left);
        int right = getheight(cur.right);
        return 1 + Math.max(left,right);
    }
}

总结

        迭代法的逻辑很简单,就是用前序、层序遍历每一个节点时,同时计算当前节点的左右孩子高度,判断当前节点的高度差是否满足平衡,如果不满足,直接返回false,如果当前节点满足,再迭代判断后面的节点。最后,如果所有节点遍历完,都没有返回false,说明二叉树的每一个节点都满足平衡条件,就返回true。

        递归法,核心逻辑是一边后序递归二叉树,一边计算当前节点的左右孩子高度,判断当前遍历节点是否满足平衡,如果不满足平衡就返回-1,如果满足平衡就计算当前节点的高度。

         递归法有四个终止条件,一是节点为null,返回0。二是节点的左右高度差>1,返回-1。还有两种情况千万不能漏,如果该节点的左孩子or右孩子的返回值=-1,说明其左孩子or右孩子已经不平衡了,直接返回-1。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

设置表格高度后,数值改变但实际不变

1.选中表格 2.点击“开始”——>“段落设置”的选项启动按钮&#xff0c;设置为单倍行距 3.可以看到&#xff0c;表格的行高被调小了。

如何高效建立企业绩效评估体系?这家世界500强企业用BI工具这么做

在目前经济下行&#xff0c;竞争激烈&#xff0c;向精细化管理要效益的社会背景下&#xff0c;如何对资金结算部门做好绩效管理&#xff0c;以保障组织的正常运作&#xff0c;是各大企业面对的重要痛点。 本文将基于某世界500强公司的财务共享资金结算部门的绩效管理办法&…

河北专升本(c语言各种编程题)

目录 第一类、递归调用 第二类、特殊数字 第三类、多维数组 第四类、字符处理 第五类、数学问题 第六类、排序算法 第七类、循环问题 第八类、进制转换 第九类、实际应用 第十类、图形输出 第一类、递归调用 1.汉诺塔&#xff1a;请输入盘子数&#xff0c;输出盘子移动…

海外媒体如何发布软文通稿

大舍传媒-带您了解海外发布新潮流 随着全球化的不断深入&#xff0c;越来越多的中国企业开始关注海外市场。为了在国际舞台上树立品牌形象&#xff0c;企业纷纷寻求与海外媒体合作&#xff0c;通过发布软文通稿的方式&#xff0c;传递正面信息&#xff0c;提升品牌知名度。作为…

【4071】基于小程序实现的活动报名管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;ssm 【…

抹机王的使用教程以及常见问题

首先请确保你已经正常安装了XPosed/EDXP/LSP框架并已激活抹机王模块&#xff0c;其中XP和EDXP模块均只需要框架内激活抹机王并重启即可&#xff0c;LSPosed注意作用域需要勾选上自己想要修改的APP&#xff08;如果你还是一意孤行只勾选系统框架那改机完全没用就是你自己的想法了…

设计模式之模板方法模式详解(下)

3&#xff09;钩子方法的使用 1.概述 钩子方法的引入使得子类可以控制父类的行为。 2.结构图 3.代码实现 将公共方法和框架代码放在抽象父类中 abstract class DataViewer {//抽象方法&#xff1a;获取数据public abstract void GetData();//具体方法&#xff1a;转换数据…

每日一题 — 最小覆盖子串

76. 最小覆盖子串 - 力扣&#xff08;LeetCode&#xff09; 解法一&#xff1a;暴力遍历哈希表 解法二&#xff1a;滑动窗口哈希表 定义left和right初始化为零&#xff0c;固定left&#xff0c;先向右遍历right&#xff0c;放到哈希表中这个时候我们需要统计有效字符的个数&…

深入挖掘C语言 ---- 文件操作

目录 1. 文件的打开和关闭1.1 流和标准流1.1.1流1.1.2标准流 1.2 文件指针1.3 文件的打开和关闭 2. 顺序读写3. 随机读写3.1 fseek3.2 ftell3.3 rewind 4. 读取结束判定 正文开始 1. 文件的打开和关闭 1.1 流和标准流 1.1.1流 我们程序的数据需要输出到各种外部设备, 也需要…

Leetcode算法训练日记 | day30

一、重新安排行程 1.题目 Leetcode&#xff1a;第 332 题 给你一份航线列表 tickets &#xff0c;其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK&#xff08;肯尼迪国际机场&#xff09;出发…

java算法day2

螺旋矩阵搜索插入位置查找元素第一个位置和最后一个位置 螺旋矩阵 解法&#xff1a;模拟&#xff0c;核心在于你怎么转&#xff0c;还有就是处理边界&#xff0c;边界如何收缩&#xff0c;什么时候停止旋转。最内圈的时候怎么处理。 通过上图的模拟来解决这个问题&#xff1a;…

数据库锁等待排查方法、命令行安装数据库及授权文件更新

欢迎关注“数据库运维之道”公众号&#xff0c;一起学习数据库技术! 本期将为大家分享“数据库锁等待排查方法、命令行安装数据库及授权文件更新”的运维技能。 关键词&#xff1a;锁等待、V$LOCK、V$TRXWAIT、死锁、锁超时、命令行部署达梦、授权文件更新 当用户反馈执行SQL语…

1985-2022年各地级市专利申请数据

1985-2022年各地级市专利申请数据 1、时间&#xff1a;1985-2022年 2、指标&#xff1a;行政区划代码、地区、省份、城市、年份、发明公布&#xff08;申请数&#xff09;、其中&#xff1a;获得授权、外观设计申请量、实用新型申请量 3、来源&#xff1a;国家知识产权局 4…

【Java】简单实现图书管理系统

前言 在本篇博客当中&#xff0c;我们会使用Java基础语法来简单实现一个图书管理系统&#xff0c;主要用到的知识为&#xff1a;封装、多态、继承、接口等等&#xff0c;并不会使用数据库来存储数据&#xff0c;请注意 需求 1. 要求设置管理员和普通用户两种身份&#xff0c…

【深度学习实战(9)】三种保存和加载模型的方式

一、state_dict方式&#xff08;推荐&#xff09; torch.save(model.state_dict(), PATH)model YourModel() model.load_state_dict(torch.load(PATH)) model.eval()记住一定要使用model.eval()来固定dropout和归一化层&#xff0c;否则每次推理会生成不同的结果。 二、整个…

实验室三大常用仪器3---交流毫伏表的使用方法(笔记)

目录 函数信号发生器、示波器、交流毫伏表如果连接 交流毫伏表的使用方法 测量值的读数问题 实验室三大常用仪器1---示波器的基本使用方法&#xff08;笔记&#xff09;-CSDN博客 实验室三大常用仪器2---函数信号发生器的基本使用方法&#xff08;笔记&#xff09;-CSDN博客…

C#自定义窗体更换皮肤的方法:创建特殊窗体

目录 1.窗体更换皮肤 2.实例 &#xff08;1&#xff09;图片资源管理器Resources.Designer.cs设计 &#xff08;2&#xff09;Form1.Designer.cs设计 &#xff08;3&#xff09;Form1.cs设计 &#xff08;4&#xff09; 生成效果 &#xff08;5&#xff09;一个遗憾 1.窗…

Git常见命令行操作和IDEA图形化界面操作

设置Git用户名和标签 在安装完Git以后需要设置用户和签名&#xff0c;至于为什么要设置用户签名可以看一下这篇文章【学了就忘】Git基础 — 11.配置Git用户签名说明 - 简书 (jianshu.com) 基本语法&#xff1a; git config --global user.name 用户名 git config --global u…

SpringBoot项目创建及简单使用

目录 一.SpringBoot项目 1.1SpringBoot的介绍 1.2SpringBoot优点 二.SpringBoot项目的创建 三.注意点 一.SpringBoot项目 1.1SpringBoot的介绍 Spring是为了简化Java程序而开发的&#xff0c;那么SpringBoot则是为了简化Spring程序的。 Spring 框架&#xff1a; Spring…

ARM之栈与方法

ARM之栈与方法 计算机中的栈是一种线性表&#xff0c;它被限定只能在一端进行插入和删除操作&#xff08;先进后出&#xff09;。通常将可以插入和删除操作的一端称为栈顶&#xff0c;相对的一端为栈底。 通常栈有递增堆栈&#xff08;向高地址方向生长&#xff09;、递减堆栈…
最新文章