二叉树11:完全二叉树的节点个数

2023-11-19

主要是我自己刷题的一些记录过程。如果有错可以指出哦,大家一起进步。
转载代码随想录
原文链接:
代码随想录
leetcode链接:222. 完全二叉树的节点个数

题目:

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

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

示例:

示例 1:

在这里插入图片描述

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

示例 2:

输入:root = []
输出:0

示例 3:

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

提示:

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

思路:

普通二叉树
首先按照普通二叉树的逻辑来求。

这道题目的递归法和求二叉树的深度写法类似, 而迭代法,二叉树:层序遍历登场!遍历模板稍稍修改一下,记录遍历的节点数量就可以了。

递归遍历的顺序依然是后序(左右中)。

递归

确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。
代码如下:

int getNodesNum(TreeNode* cur) {

确定终止条件:如果为空节点的话,就返回0,表示节点数为0。
代码如下:

if (cur == NULL) return 0;

确定单层递归的逻辑:先求它的左子树的节点数量,再求右子树的节点数量,最后取总和再加一 (加1是因为算上当前中间节点)就是目前节点为根节点的节点数量。
代码如下:

int leftNum = getNodesNum(cur->left);      // 左
int rightNum = getNodesNum(cur->right);    // 右
int treeNum = leftNum + rightNum + 1;      // 中
return treeNum;

所以整体C++代码如下:

// 版本一
class Solution {
private:
    int getNodesNum(TreeNode* cur) {
        if (cur == NULL) return 0;
        int leftNum = getNodesNum(cur->left);      // 左
        int rightNum = getNodesNum(cur->right);    // 右
        int treeNum = leftNum + rightNum + 1;      // 中
        return treeNum;
    }
public:
    int countNodes(TreeNode* root) {
        return getNodesNum(root);
    }
};

代码精简之后C++代码如下:

// 版本二

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == NULL) return 0;
        return 1 + countNodes(root->left) + countNodes(root->right);
    }
};

时间复杂度:O(n)
空间复杂度:O(log n),算上了递归系统栈占用的空间

网上基本都是这个精简的代码版本,其实不建议大家照着这个来写,代码确实精简,但隐藏了一些内容,连遍历的顺序都看不出来,所以初学者建议学习版本一的代码,稳稳的打基础。

迭代法

那么只要模板少做改动,加一个变量result,统计节点数量就可以了


```cpp
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)
空间复杂度:O(n)

完全二叉树

以上方法都是按照普通二叉树来做的,对于完全二叉树特性不了解的同学可以看这篇 关于二叉树,你该了解这些! (opens new window),这篇详细介绍了各种二叉树的特性。

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

大家要自己看完全二叉树的定义,很多同学对完全二叉树其实不是真正的懂了。

我来举一个典型的例子如题:
在这里插入图片描述
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。

对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。

对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。

完全二叉树(一)如图:
在这里插入图片描述
完全二叉树(二)如图:
在这里插入图片描述
可以看出如果整个树不是满二叉树,就递归其左右孩子,直到遇到满二叉树为止,用公式计算这个子树(满二叉树)的节点数量。

这里关键在于如何去判断一个左子树或者右子树是不是满二叉树呢?

在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。如图:
在这里插入图片描述
在完全二叉树中,如果递归向左遍历的深度不等于递归向右遍历的深度,则说明不是满二叉树,如图:
那有录友说了,这种情况,递归向左遍历的深度等于递归向右遍历的深度,但也不是满二叉树,如题:
在这里插入图片描述
如果这么想,大家就是对 完全二叉树理解有误区了,以上这棵二叉树,它根本就不是一个完全二叉树!

判断其子树是不是满二叉树,如果是则利用公式计算这个子树(满二叉树)的节点数量,如果不是则继续递归,那么 在递归三部曲中,第二部:终止条件的写法应该是这样的:

if (root == nullptr) return 0; 
// 开始根据做深度和有深度是否相同来判断该子树是不是满二叉树
TreeNode* left = root->left;
TreeNode* right = root->right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
while (left) {  // 求左子树深度
    left = left->left;
    leftDepth++;
}
while (right) { // 求右子树深度
    right = right->right;
    rightDepth++;
}
if (leftDepth == rightDepth) {
    return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,返回满足满二叉树的子树节点数量
}

递归三部曲,第三部,单层递归的逻辑:(可以看出使用后序遍历)

int leftTreeNum = countNodes(root->left);       // 左
int rightTreeNum = countNodes(root->right);     // 右
int result = leftTreeNum + rightTreeNum + 1;    // 中
return result;

该部分精简之后代码为:

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

最后整体C++代码如下:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr) return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
        while (left) {  // 求左子树深度
            left = left->left;
            leftDepth++;
        }
        while (right) { // 求右子树深度
            right = right->right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftDepth初始为0
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

时间复杂度:O(log n × log n)
空间复杂度:O(log n)

自己的代码

class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root) return 0;
        queue<TreeNode* >que;
        que.push(root);
        int nodeNum = 0;
        while(!que.empty()){
            int size = que.size();
            nodeNum+=size;
            for(int i=0;i<size;i++){
                TreeNode* temp = que.front();
                que.pop();
                if(temp->left) que.push(temp->left);
                if(temp->right) que.push(temp->right);
            }
        }
        return nodeNum;
    }
};

class Solution {
public:
       int countNodes(TreeNode* root) {
        if(!root)return 0;
        int leftNodeNum=countNodes(root->left);
        int rightNodeNum=countNodes(root->right);
        return 1+leftNodeNum+rightNodeNum;
    }
};


class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root) return 0;
        int leftNodeNum=0,rightNodeNum=0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;

        while(left){
            left=left->left;
            leftNodeNum++;
        }

        while(right){
            right=right->right;
            rightNodeNum++;
        }
        if(leftNodeNum==rightNodeNum)  return (2 << leftNodeNum) - 1;
        return countNodes(root->left)+countNodes(root->right)+1;

    }
};
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

二叉树11:完全二叉树的节点个数 的相关文章

随机推荐

  • vscode实现文件单步调试保姆级教程

    第一步 第二步 第三步 第四步 第五步 第六步 第七步 第八步 第九步 第十步 点击终端 gt 配置任务 第十一步 第十二步 第十三步 第十四步 设置完毕 可以在源程序打断点按F5执行了
  • Spring中Quartz的详细配置

    关于cron表达式 来自网络 Cron 表达式包括以下 7 个字段 秒 分 小时 月内日期 月 周内日期 年 可选字段 特殊字符 Cron 触发器利用一系列特殊字符 如下所示 反斜线 字符表示增量值 例如 在秒字段中 5 15 代表从第 5
  • 常见状态码

    SWITCH PROTOCOL 101 Switching Protocols OK 200 OK CREATED 201 Created ACCEPTED 202 Accepted NO CONTENT 204 No Content PA
  • 雷军 1994 年写的代码,经典老古董~

    整合整理 程序员的那些事 id iProgrammer 雷军的代码像诗一样优雅 有些网友在评论中质疑 说雷军代码不会是 屎 一样优雅吧 说这话的网友 也许是开玩笑的 也许是真没看过雷军写过的代码 在 2011 年的时候 我们在微博转过雷军在
  • 《计算机网络》——第四章知识点

    1 终点不可达 当路由器或主机不能交付数据报时就向源点发送终点不可达报文 无法交付 源点抑制 当路由器或主机由于拥塞而丢弃数据报时 就向源点发送源点抑制报文 使源点知道应当把数据报的发送速率放慢 拥塞丢数据 3 时间超过 当路由器收到生存时
  • [UE5蓝图基础一]13.类似”人类一败涂地”掉落一定距离会回到空中 最终着落点还是设定地形上

    利用合体触发器Box Conllision 目标点 在放置actor里 实现 修改盒体范围为2W 当人物与盒子重叠就瞬移到空中
  • 苹果美区app内购方法及经验

    苹果美区app内购方法及经验 方法一 礼品卡 失败 淘宝or亚马逊购买苹果礼品卡 经测试账号充值成功 也可以购买付费app 但内购会经典限购 等了n周依然没有解除 如果养号成功大概就没什么问题 但苯人等不及了 方法二 美区转国区 实在太想氪
  • 编译安装mysql5.7.10

    1 gt cmake MySQL使用cmake跨平台工具预编译源码 用于设置mysql的编译参数 如 安装目录 数据存放目录 字符编码 排序规则等 安装最新版本即可 2 gt make3 75 mysql源代码是由C和C 语言编写 在Lin
  • 算法 {掃描線}

    算法 掃描線 掃描線 定義 題目 二維空間上 給定若干個 凸多邊形 求他們的並集的面積 思路 用若干個x 與Y軸平行的線 將目標區域T劃分成若干個子區域Ai 即S A1 A2 然後單獨求每個Ai 性質 與積分有點類似 都是求一個區域的面積
  • SQLite、MySQL和PostgreSQL 三种关系数据库哪个好?

    https www ssdax com 2188 html
  • 优化MyBatisPlus的autoResultMap生成策略

    前言 使用MyBatis Plus的字段类型处理器 只需一个注解 就可以很方便的将数组 对象等数据直接映射到实体类中 Data Accessors chain true TableName autoResultMap true public
  • Android 12读写存储卡权限申请

  • mysql报错:Host is not allowed to connect to this MySQL server(设置远程连接)

    一般出现在 localhost可以连接mysql 但是远程不行 输入shell命令 mysql u root p 然后输入密码进入mysql mysql命令行输入 use mysql update user set host where u
  • Linux-centos

    目录 一 Linux入门概述 1 1概述 1 2 下载地址 1 3 Linux特点 1 4 Linux和Windows区别 二 Linux目录结构 2 1 概览 2 2 树状目录结构 三 VI VIM编辑器 3 1 概述 3 2 测试数据准
  • 链队列的基本操作

    define CRT SECURE NO WARNINGS 链栈 include
  • Scala语言入门

    Scala入门 一 Scala安装 二 类和对象 1 Scala基本数据类型 2 Scala定义类 3 Scala单例对象 4 伴生对象 5 控制抽象 三 简单语法 1 if else 2 循环 3 方法 4 字符串 5 数组 6 集合 四
  • 你这样写代码会被打!

    编译 Python 开发者 伯乐在线 http python jobbole com 89252 所有人 好吧 不是所有人 都知道 python 是一门用途广泛 易读 而且容易入门的编程语言 但同时 python 语法也允许我们做一些很奇怪
  • 实现物联网,你有使用合适的数据库吗?

    数据正不断影响关键业务的决策 这使得企业开始重新考虑 他们能从物联网中得到什么 如果你觉得物联网世界的不断增长只是一时的狂热 那你就错了 一份关于M2M技术的研究报告表明 到2020年 通过传感器控制 监控以及自动化管理的设备将达到125亿
  • 嵌入式 在开发板显示bmp图片、jpeg图片

    嵌入式 在开发板显示bmp图片 jpeg图片 一 简述 记 在GEC6818开发板 800W 480H 显示24位的bmp图片 使用开源的jpeg库显示jpeg图片 代码 链接 https pan baidu com s 1G3jzvdnc
  • 二叉树11:完全二叉树的节点个数

    主要是我自己刷题的一些记录过程 如果有错可以指出哦 大家一起进步 转载代码随想录 原文链接 代码随想录 leetcode链接 222 完全二叉树的节点个数 题目 给你一棵 完全二叉树 的根节点 root 求出该树的节点个数 完全二叉树 的定