算法力扣刷题记录 四十四【222.完全二叉树的节点个数】

前言

二叉树篇继续。
记录 四十四【222.完全二叉树的节点个数】


一、题目阅读

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

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

示例 1:
在这里插入图片描述

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

示例 2:

输入:root = []
输出:0

示例 3:

输入:root = [1]
输出:1

提示:

树中节点的数目范围是[0, 5 * 10^4]
0 <= Node.val <= 5 * 10^4
题目数据保证输入的树是 完全二叉树

进阶:遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?


二、尝试实现

思路

(1)统计节点个数:把完全二叉树当成一个普通的树,按照二叉树的遍历,num++ 即可。遍历方式:前中后序;实现:递归和迭代。一共6种,都是通过遍历整个树,顺便统计。如何遍历在【专栏】记录三十五、三十六学习练习过。
(2)但是题目给了完全二叉树。就想用完全二叉树的性质来实现:

  • 通过while循环可以获得完全二叉树的深度。
  • 在最后一层之上,肯定是满的。所以for循环统计了除最后一层之外的节点个数。
  • 那么最后一层该怎么统计?(卡住……)
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root) return 0;
        int sum = 0;
        int height = 1;
        TreeNode* left = root->left;
        while(left){
            height++;
            left = left->left;
        }
        for(int i = 0;i< height-1;i++){
            sum = sum*2 + 1;
        }
        //统计最后一层
        
    }
};

三、参考学习

参考思路链接

学习内容

方法一:遍历实现

  1. 思路:按后序(左右中),求出左子树的节点个数;再求右子树的节点个数;回到中间节点,两边相加后再加1;这个逻辑可以重复传递。所以递归实现,类似这篇求深度。

  2. 代码实现:

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    public:
        int getnum(TreeNode* cur){
            //终止条件
            if(!cur) return 0;
            int leftnum = getnum(cur->left);
            int rightnum  = getnum(cur->right);
            return leftnum+rightnum+1;
        }
        int countNodes(TreeNode* root) {
            return getnum(root);
        }
    };
    
    或者:直接在countNodes中递归实现:
    class Solution {
    public:
        int countNodes(TreeNode* root) {
            if(!root) return 0;
            int leftnum = countNodes(root->left);
            int rightnum = countNodes(root->right);
            return leftnum+rightnum+1;
        }
    };
    
  3. 如果前序遍历实现,中序,后序同理:

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    public:
        int num;
        void traversal(TreeNode* cur){
            if(!cur) return ;
            num++;
            traversal(cur->left);
            traversal(cur->right);
        }
        int countNodes(TreeNode* root) {
            num = 0;
            traversal(root);
            return num ;
        }
    };
    

方法二:利用完全二叉树的性质

  1. 思路:完全二叉树除最后一层外,就是满二叉树,和满二叉树有一定联系;满二叉树计算套公式:节点总数是2n-1,n是深度。
  • 如果左子树是满二叉树,计算出深度,可以利用公式求节点总数;
  • 如果右子树是满二叉树,计算出深度,可以利用公式求节点总数;
  • 如果不是满二叉树,再深入到左(右)子树内部找满二叉树,只要找到满二叉树就可以统一用公式。最后的叶子节点,一定算满二叉树。
  • 所以这就有递归的逻辑。
  1. 怎么确定是满二叉树呢?题目说输入是完全二叉树。如果一直left到叶子节点的深度=一直right到叶子节点的深度,说明这是满二叉树。

  2. 代码实现:

    /**
     * Definition for a binary tree node.
     * struct TreeNode {
     *     int val;
     *     TreeNode *left;
     *     TreeNode *right;
     *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
     *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
     *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
     * };
     */
    class Solution {
    public:
        int getnum(TreeNode* cur){
        	//如果是空,终止条件
            if(!cur) return 0;
            //求左边深度
            int leftdepth = 1;
            TreeNode* left = cur->left;
            while(left){
                leftdepth++;
                left = left->left;
            }
            //求右边深度
            int rightdepth = 1;
            TreeNode* right = cur->right;
            while(right){
                rightdepth++;
                right= right->right;
            }
            if(leftdepth == rightdepth){    //这是满二叉树,直接得到子树节点总数,不用递归深入。
                return (1<<leftdepth) - 1;//<<是二进制左移运算符
            }
            //不是满二叉树,深入递归。
            int leftnum = getnum(cur->left);
            int rightnum = getnum(cur->right);
            return leftnum+rightnum+1;//返回左子树+右子树+1
        }
        int countNodes(TreeNode* root) {
            return getnum(root);
        }
    };
    

    对比参考代码:

    • 参考给初始leftdepth = 0;rightdepth = 0;,相当于深度初始计数0开始,所以在if(leftdepth == rightdepth)里return (2<<leftdepth) - 1。
    • 但是改成深度初始计数1,那么return (1<<leftdepth) - 1。

总结

【222.完全二叉树的节点个数】
在这里插入图片描述
(欢迎指正,转载标明出处)

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

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

相关文章

Java时间复杂度介绍以及枚举

时间复杂度 从小到大&#xff1a; O(1) 常数阶。复杂度为O(1)与问题规模无关 线性阶 O&#xff08;n&#xff09;比如一个for循环中代码执行n遍 n阶 对数阶 int n9; int i1; while(i<n) { i*2; } 2^x>n时候退出。次数xlog2^n 时间复杂度为O(logN) 根号阶 int…

09 函数基础

目录 一、定义一个函数 二、调用函数 三、函数的参数 1.形参和实参 2. 参数的分类 3.参数默认值 4.参数类型说明 5.不定长参数 四、函数的返回值 1.定义 2.关键字return 五、变量的作用域 六、匿名函数 七、实参高阶函数 1.定义 2.常见实参高阶函数 max、min、so…

数据结构回顾(Java)

1.数组 线性表 定义的方式 int[] anew int[10] 为什么查询快&#xff1f; 1.可以借助O(1)时间复杂度访问某一元素&#xff0c; 2.地址连续&#xff0c;逻辑连续 3.数组长度一旦确定就不可以被修改 当需要扩容的时候需要将老数组的内容复制过来 在Java中数组是一个对象 Ar…

SpringBoot开发的AI导航站技术架构剖析 —— 技术如何选型 - 第520篇

历史文章&#xff08;文章累计520&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 《…

C#与PLC通信——如何设置电脑IP地址

前言&#xff1a; 我们与PLC通过以太网通信时&#xff0c;首先要做的就是先设置好电脑的IP&#xff0c;这样才能实现上位机电脑与PLC之间的通信&#xff0c;并且电脑的ip地址和PLC的Ip地址要同处于一个网段&#xff0c;比如电脑的Ip地址为192.168.1.1&#xff0c;那么PLC的Ip地…

【Android面试八股文】请描述一下 android 的系统架构?

Android 是一个基于 Linux 的开源软件堆栈,针对多种不同设备类型打造。下图显示了 Android 平台的主要组件。 早期的Android架构如下图所示 官方网站最新的Android平台架构图,如下所示: Linux 内核 Android 平台的基础是 Linux 内核。例如,Android 运行时 (ART) 依赖…

css-grid布局(栅格布局)

css新世界-auto-fit grid 一个比flex更强大的布局,适合做整体布局 grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); auto-fit的话有strech效果gap 不仅可以用于grid 也可用flex. 在grid-template-areas表示这个位置空着grid area 的 [a b]命名可重复命名 表示的…

RHCA II之路---EX442-6

RHCA II之路---EX442-6 1. 题目2. 解题3. 确认 1. 题目 2. 解题 sysctl -a|grep shmall echo kernel.shmall 367001 >> /etc/sysctl.conf sysctl -p3. 确认 去人这里max total shared memory的值使我们之前设定的即可.这里的值单位是kb所以只需要2个1024就可以了 ipc…

如何快速区分电子原件极性

表贴式电阻电容无极性 1表贴式.二极管 如图所示:有横杠的表示负极&#xff08;竖杠标示&#xff09;&#xff0c;注意一定要查阅数据手册在引脚信息栏一般会有 铝电解电容 手册一般会对正负极有说明 钽电容有极性 发光二极管 芯片 一般规律&#xff1a;1.看丝印朝向正对丝印的…

监控易V7.6.6.15升级详解7,日志分析更高效

随着企业IT系统的日益复杂&#xff0c;日志管理成为了保障系统稳定运行、快速定位问题的重要工具。为了满足广大用户对日志管理功能的更高需求&#xff0c;监控易系统近日完成了重要版本升级&#xff0c;对日志管理功能进行了全面优化和新增。 一、Syslog日志与SnmpTrap日志统…

uniapp踩坑之项目:uni-table垂直居中和水平居中

uni-table 中的水平居中uni-td align"center" //html 水平居中<uni-table ref"table" :loading"loading" border stripe emptyText"暂无更多数据"><uni-tr><uni-th :width"tdWidth/6" align"center&quo…

7-Zip解压缩软件

7-Zip是一款完全免费而且开源的压缩软件&#xff0c;相比其他软件有更高的压缩比而且相对于WinRAR不会消耗大量资源 下载地址&#xff1a;7-Zip解压缩软件安装包_压缩软件安装包资源-CSDN文库

【Python3】自动化测试_用Playwright操作浏览器

创建浏览器实例 # 启动浏览器实例 myBrowser myPlaywright.chromium.launch(headlessFalse) # myBrowser myPlaywright.firefox.launch(headlessFalse) # myBrowser myPlaywright.webkit.launch(headlessFalse) args < List [ str ] >传递给浏览器实例的附加参数。 c…

仓颉语言 -- 函数

1、定义函数 仓颉使用关键字 func 来表示函数定义的开始&#xff0c;func 之后依次是函数名、参数列表、可选的函数返回值类型、函数体。其中&#xff0c;函数名可以是任意的合法标识符&#xff0c;参数列表定义在一对圆括号内&#xff08;多个参数间使用逗号分隔&#xff09;…

PyTorch论文

2019-12 PyTorch: An Imperative Style, High-Performance Deep Learning Library 设计迎合4大趋势&#xff1a; 1. array-based (Tensor) 2. GPU加速 3. 自动求导 (Auto Differentiation) 4. 拥抱Python生态 4大设计原则&#xff1a; 1. 使用算法和数据开发者熟悉的Python做编…

【Python学习笔记】:Python爬取音频

【Python学习笔记】&#xff1a;Python爬取音频 背景前摇&#xff08;省流可以不看&#xff09;&#xff1a; 人工智能公司实习&#xff0c;好奇技术老师训练语音模型的过程&#xff0c;遂请教&#xff0c;得知训练数据集来源于爬取某网页的音频。 很久以前看B站同济子豪兄的《…

开源AI生成连续一致性儿童故事书; GraphRAG结合本地版Ollama;AI辅助老年人用餐;开源无代码AI工作流VectorVein

✨ 1: SEED-Story SEED-Story 是一种能生成包含一致性图像的多模态长篇故事的机器学习模型&#xff0c;配套数据集已开放。 SEED-Story 是一种多模态长故事生成模型&#xff0c;具备生成包含丰富且连贯的叙事文本和一致性高的人物和风格图像的能力。此模型基于 SEED-X 构建。…

找到完美的横道图工具:2024年选择指南

国内外主流的10款项目进度横道图软件对比&#xff1a;PingCode、Worktile、灵动计划&#xff08;Wolai&#xff09;、飞书项目、Tapd、麦客CRM、Asana、Trello、Smartsheet、Basecamp。 在管理项目时&#xff0c;确保所有进度和任务都按计划进行是每个项目经理面临的一大挑战。…

iSAM: Incremental Smoothing and Mapping

文章目录 iSAM原理主要思想问题描述求解方法增量求解增量更新增量因式分解(基于[Givens Rotations](https://blog.csdn.net/weixin_41469272/article/details/140245327)) 回环处理数据association变量组合协方差 补充知识COLAMD排序算法原理步骤 JVC assignment iSAM原理 论文…

QT--控件篇二

一、文本框 1. QLineEdit 文本框通常使用QLineEdit和QTextEdit这两个类来实现。 QLineEdit&#xff1a;用于单行文本输入。QTextEdit&#xff1a;用于多行文本输入&#xff0c;可以包含丰富的文本格式。 用setText(QString txt);设置默认的显示内容&#xff0c;用QString tex…