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

news2024/9/23 15:27:50

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

文章目录

      • [222. 完全二叉树的节点个数](https://leetcode.cn/problems/count-complete-tree-nodes/)
        • 一、题目
        • 二、题解
          • 方法一:递归遍历所有结点
          • 方法二:根据完全二叉树的特性递归
          • 方法三:迭代


一、题目

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

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

示例 1:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lwEHz76F-1690683955682)(D:\A_WHJ\Computer Science\typora图片\complete.jpg)]

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

示例 2:

输入:root = []
输出:0

示例 3:

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

提示:

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

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

二、题解

方法一:递归遍历所有结点

算法思路

  1. 首先,判断根节点是否为空,如果为空,则直接返回节点个数为 0。
  2. 统计当前节点的左子树和右子树的节点数:
    • 通过递归调用 countNodes 函数,分别计算当前节点的左子树和右子树的节点个数。这里会涉及到递归的调用,将逐层深入到树的叶子节点,然后逐层返回结果。
  3. 计算当前节点及其子树的节点个数:
    • 通过左子树节点数和右子树节点数,加上当前节点自身,得到当前节点及其子树的节点个数。
  4. 返回节点个数:
    • 最后,返回当前节点及其子树的节点个数。

具体实现

/**
 * 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) {
        int count = 0;
        if(root == nullptr) return 0;
        if(root->left) count++;
        if(root->right) count++;
        int left_count = countNodes(root->left);
        int right_count = countNodes(root->right);
        count = left_count + right_count + 1;
        if(root->left == nullptr && root->right == nullptr){
            return count;
        }
        return count;
    }
};

算法分析

时间复杂度分析:在最坏情况下,每个节点都需要被访问一次,所以时间复杂度为 O(n),其中 n 是二叉树的节点个数。

空间复杂度分析:在递归过程中,除了栈空间用于函数调用,我们没有使用额外的空间,所以空间复杂度为 O(h),其中 h 是二叉树的高度。在最坏情况下,二叉树可能退化成链表,高度为 n,所以最坏情况下的空间复杂度为 O(n)。

方法二:根据完全二叉树的特性递归

算法思路

对于完全二叉树,除了最底层可能没有填满外,其余每层的节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。所以,我们可以利用完全二叉树的高度和满二叉树的节点数量的关系来判断节点数。

假设完全二叉树的高度为 h,如果左子树的高度等于右子树的高度,说明左子树是一棵满二叉树,可以直接计算节点数:2^h - 1。否则,我们继续递归地计算左右子树的节点数,直到遇到满二叉树为止。

具体实现

  1. 首先,判断根节点是否为空,如果为空,则直接返回节点个数为 0。

  2. 计算左子树和右子树的高度:

    我们可以用两个指针 left_childright_child 分别从根节点开始,沿着左子树和右子树一直向左移动,直到到达叶子节点,此时的高度就是左子树和右子树的高度。

  3. 判断是否为满二叉树:

    比较左子树和右子树的高度,如果相等,则说明左子树是满二叉树,直接计算满二叉树的节点数:2^h - 1,并返回结果。

  4. 递归计算左子树和右子树的节点数:

    如果左子树的高度不等于右子树的高度,继续递归地计算左右子树的节点数,直到遇到满二叉树为止。

  5. 返回节点个数:

    最后,将计算出的左子树节点数、右子树节点数以及根节点自身的节点数相加,就得到了完整的二叉树的节点数。

/**
 * 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 == nullptr)
            return 0;

        int left_height = 0, right_height = 0;
        TreeNode* left_child = root;
        TreeNode* right_child = root;

        // 计算左子树和右子树的高度
        while (left_child) {
            left_height++;
            left_child = left_child->left;
        }

        while (right_child) {
            right_height++;
            right_child = right_child->right;
        }

        // 如果左子树的高度等于右子树的高度,说明左子树是满二叉树
        if (left_height == right_height)
            return (1 << left_height) - 1;

        return 1 + countNodes(root->left) + countNodes(root->right);
    }
};

算法分析

时间复杂度分析:在最坏情况下,需要遍历完整个树的高度,所以时间复杂度为 O(log n)。

空间复杂度分析:在递归过程中,除了树的高度外,我们没有使用额外的空间,所以空间复杂度为 O(log n)。

方法三:迭代

算法分析

  1. 首先,判断根节点是否为空,如果为空,则直接返回节点个数为 0。
  2. 使用队列 que 来进行层序遍历:
    • 将根节点压入队列 que 中,表示从根节点开始进行层序遍历。
    • 利用循环,不断从队列中取出节点,并检查该节点的左右子节点,如果存在则将其压入队列。
  3. 统计节点个数:
    • 使用 result 变量记录节点的数量。每次从队列中取出一个节点,就将 result 加 1,表示访问了一个节点。
  4. 返回节点个数:
    • 最后,当队列为空,即遍历完成时,返回 result,即得到了节点的总数。

具体实现

class Solution {
public:
    int countNodes(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        int result = 0;
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                result++;   // 记录节点数量
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return result;
    }
};

算法分析

时间复杂度分析:在最坏情况下,每个节点都需要被访问一次,所以时间复杂度为 O(n),其中 n 是二叉树的节点个数。

空间复杂度分析:在最坏情况下,队列中需要存储一层的节点,所以空间复杂度为 O(w),其中 w 是二叉树最宽的层的节点个数。在最坏情况下,二叉树可能退化成链表,最宽的层会有 n/2 个节点,所以最坏情况下的空间复杂度为 O(n)。

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

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

相关文章

[C语言] 数组

1. 一维数组的创建和初始化 2. 一维数组的使用 3. 一维数组在内存中的存储 4. 二维数组的创建和初始化 5. 二维数组的使用 6. 二维数组在内存中的存储 7. 数组越界 8. 数组作为函数参数 9. 数组的应用实例 1 &#xff1a;三子棋 10. 数组的应用实例 2 &#…

初阶数据结构——二叉树题目

文章目录 一、单值二叉树二、检查两颗树是否相同三、另一棵树的子树四、二叉树的前序遍历五、对称二叉树 一、单值二叉树 单值二叉树 如果二叉树每个节点都具有相同的值&#xff0c;那么该二叉树就是单值二叉树。只有给定的树是单值二叉树时&#xff0c;才返回 true&#xff…

AD原理图检查ERC(编译检查)

原理图的编译&#xff1a; 原理图界面选择菜单栏的&#xff1a;工程---->Compile PCB Project 也可以项目管理栏右击对应项目文件 在右下角&#xff0c;点击panels---->Message&#xff0c;就可以打开Message界面 原理图的常用检测&#xff1a; 原理图界面选择菜单…

kv键值对快速转换为json串(字典类型) | 批量添加双引号

从浏览器中复制的以下数据, 并不能直接使用 refresh:0 start:0 count:20 selected_categories:%7B%7D uncollect:false playable:true tags:在python中需转为字典类型 {refresh: 0,start: 0,count: 20,selected_categories: %7B%7D,uncollect: false,playable: true,tags: , …

SIMD系列-GATHER/SCATTER操作

SIMD系列-GATHER/SCATTER操作 众所周知&#xff0c;SIMD寄存器可以使用LOAD/STORE操作与标量域&#xff08;或者更准确的说是内存&#xff09;进行通信。这些操作的缺点是&#xff1a;只允许移动内存中连续的数据元素。然而&#xff0c;我们代码中&#xff0c;经常需要访问非连…

浅谈大数据软件的功能性分析

在当今时代的潮流中&#xff0c;工作中遇到大数据处理的时候非常多&#xff0c;因此需要一些大数据分析软件帮助人们进行工作。由于这些软件针对的对象不同&#xff0c;因此使用方法也不同&#xff0c;那么为了帮助更多的人了解大数据分析软件&#xff0c;我们就对这些软件的功…

【Linux命令200例】mc一个十分实用的文件管理器

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜活的实操案例对各个命令进行深入…

ARM裸机-4

1、什么是交叉编译 1.1、两种开发模式 非嵌入式开发&#xff0c;A&#xff08;类&#xff09;机编写&#xff08;源代码&#xff09;、编译得到可执行程序&#xff0c;发布给A&#xff08;类&#xff09;机运行。 嵌入式开发&#xff0c;A&#xff08;类&#xff09;机编写&am…

【PWN · Stack Smash】[2021 鹤城杯]easyecho

花式栈溢出——Canary保护是吧&#xff1f;接化发&#xff0c;拿来吧你 目录 前言 一、代码分析 0.保护 1.main函数 2.sub_CF0()函数 &#xff08;v9指向的函数&#xff09; 二、Stack Smash过程 0.原理简述 1.条件与准备 2.地址泄露 ①真实地址泄露 ②flag地址泄露…

解决问题:python PermissionError: [WinError 5]拒绝访问

重要&#xff1a;关闭PyCharm Community Edition 2022.3等与python相关的编程程序找到按照python解释器的位置python->右键>属性>安全->点击组或用户名"中的Users->编辑点击"组或用户名"中的Users->把"完全控制"打钩->应用->…

【Java】使用JDBC操作MySQL(快速入门+详解)

文章目录 1. JDBC概述2. JDBC快速入门2.1 下载驱动jar包2.2 数据准备2.3 创建工程2.4 编写代码 3. JDBC API详解3.1 DriverManager3.2 Connection3.2.1 获取执行SQL对象3.2.1 管理事务 3.3 Statement3.3.1 执行DML语句3.3.2 执行DDL语句 3.4 ResultSet3.4.1 ResultSet对象方法3…

ChatGPT 实现前一天

提出需求 个人输入需求&#xff1a; Java实现键盘输入日期 输出前一天&#xff0c;需要考虑润年和非润年&#xff0c;2月是否有29号&#xff0c;大月小月的区分等细节处理&#xff0c;不符合的有对应提示&#xff0c;不使用java包里的封装好的类 ChatGPT4分析出的语义&#xff…

人工智能安全-2-非平衡数据处理

0 提纲 现象与原因非平衡数据处理方法概览数据预处理层面特征层算法层面1 现象与原因 非平衡数据分类问题:在网络信息安全问题中,诸如恶意软件检测、SQL注入、不良信息检测等许多问题都可以归结为机器学习分类问题。这类机器学习应用问题中,普遍存在非平衡数据的现象。 产…

哈希函数如何工作 ?

动动发财的小手&#xff0c;点个赞吧&#xff01; 作为一名程序员&#xff0c;您每天都会使用哈希函数。它们在数据库中用于优化查询&#xff0c;在数据结构中用于使速度更快&#xff0c;在安全性中用于保证数据安全。几乎每次与技术的交互都会以某种方式涉及哈希函数。 哈希函…

生命在于学习——APP渗透学习笔记

一、app渗透篇 1、Android 简介 自从 Android 被谷歌收购&#xff08;2005 年&#xff09;&#xff0c;谷歌已经完成了整个开发&#xff0c;在过去的 9 年里&#xff0c;尤其是在安全方面&#xff0c;有很多变化。 现在&#xff0c;它是世界上最广泛使用的智能手机平台&#…

代码、低代码、无代码开发触手可及的低代码平台源码

基于moleculer微服务架构开发的低代码平台源码&#xff0c;代码、低代码、无代码开发触手可及。 一、低代码平台系统功能 【公司信息】 管理员可通过页面顶部设置菜单或者应用程序中设置应用进入到后台设置页面。 在公司信息页面可进行基础信息修改&#xff0c;启用用户自助…

我在CSDN创作的第五十天

这篇文章主要是写给自己的&#xff0c;是对自己现在阶段的一个认识&#xff0c;6月10号&#xff0c;我在CSDN发布了第一篇文章&#xff0c;距离现在不多不少&#xff0c;刚刚好是50天&#xff0c;期间创作的都是C语言的一些内容&#xff0c;我创作的文章也都是我现在所学的知识…

Django系列之DRF简单使用

基于ModelViewSets的简单使用 models.py from django.db import modelsclass AuthorDetail(models.Model):gender models.CharField(max_length8)birthday models.DateField()telephone models.BigIntegerField()addr models.CharField(max_length64)class Author(models…

手机的python怎么运行文件,python在手机上怎么运行

大家好&#xff0c;小编来为大家解答以下问题&#xff0c;手机上的python怎么运行程序&#xff0c;手机的python怎么运行文件&#xff0c;今天让我们一起来看看吧&#xff01; 1、python程序怎么在手机上运行 python语言应用很广泛&#xff0c;自己也很喜欢使用它&#xff0c;其…

自学网络安全(黑客)入门

自学网络安全入门可以按照以下步骤进行&#xff1a; 确定学习目标&#xff1a;网络安全是一个广泛的领域&#xff0c;包括密码学、网络防御、漏洞利用等方面。确定自己想要学习的具体方向&#xff0c;可以更好地规划学习路线。 学习基础知识&#xff1a;网络安全的基础知识包括…