【算法与数据结构】222、LeetCode完全二叉树的节点个数
文章目录
- 一、题目
- 二、一般遍历解法
- 三、利用完全二叉树性质
- 四、完整代码
所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。
一、题目
二、一般遍历解法
思路分析:利用层序遍历,然后用num++记录节点数量。其他的例如递归法和迭代法也是如此。
层序遍历程序如下:
class Solution {
public:int countNodes(TreeNode* root) {if (!root) return 0;queue<TreeNode*> que;que.push(root);int num = 0; // 节点数量while (!que.empty()) {int size = que.size(); // size必须固定, que.size()是不断变化的for (int i = 0; i < size; ++i) { TreeNode* node = que.front();que.pop();num++;if (node->left) que.push(node->left); // 空节点不入队if (node->right) que.push(node->right);}}return num;}
};
复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n)。
- 空间复杂度: O ( n ) O(n) O(n)。
递归程序如下(这应该是最精简的版本了):
class Solution2 {
public:int countNodes(TreeNode* root) {return root == NULL ? 0 : countNodes(root->left) + countNodes(root->right) + 1;}
};
三、利用完全二叉树性质
思路分析:完全二叉树具有一个特性,假设它的深度为K,它的节点个数在 [ 2 K − 1 − 1 , 2 K − 1 ] [2^{K-1}-1, 2^K-1] [2K−1−1,2K−1]之间,意味着它只有两种情况,一种是满二叉树,一种是最后一层叶子节点没有满。对于情况一可以用 2 K − 1 2^K-1 2K−1来计算,对于情况二分别递归其左子树和右子树,递归到一定深度一定有左子树或者右子树为满二叉树,然后按照情况一来计算。那么满二叉树的最左边节点和最右边节点的深度一定是相等的,依据这个特性判断子树是否为满二叉树。
递归程序当中,我们要确定三个步骤,1、输入参数,返回值 2、递归终止条件 3、单层递归逻辑。输入参数为中间节点,返回值为左子树的节点数量+右子树节点数量+1(+1是加上中间节点)。当节点为空时,递归终止,返回0。每次递归我们都要计算最左/右边节点深度,然后判断二者是否相等,如果相等则是满二叉树,返回 2 K − 1 2^K-1 2K−1,K为深度。程序当中使用了左移运算符,因为运算符的优先级问题,记得加括号。左移运算符是二进制运算,计算机计算的更快。
程序如下:
class Solution3 {
public:// 利用完全二叉树的性质,递归法int countNodes(TreeNode* root) {if (!root) return 0;TreeNode* left = root->left;TreeNode* right = root->right;int Ldepth = 0, Rdepth = 0;while (left) { // 递归左子树left = left->left;Ldepth++;}while (right) { // 递归右子树right = right->right;Rdepth++;}if (Ldepth == Rdepth) {return (2 << Ldepth) - 1; // <<为左移运算符(位运算符),相当于2*leftDepth,但二进制运算计算机算的更快}return countNodes(root->left) + countNodes(root->right) + 1;}
};
复杂度分析:
- 时间复杂度: O ( n ) O(n) O(n)。
- 空间复杂度: O ( n ) O(n) O(n)。
四、完整代码
# include <iostream>
# include <vector>
# include <queue>
# include <string>
# include <algorithm>
using namespace std;// 树节点定义
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;queue<TreeNode*> que;que.push(root);int num = 0; // 节点数量while (!que.empty()) {int size = que.size(); // size必须固定, que.size()是不断变化的for (int i = 0; i < size; ++i) { TreeNode* node = que.front();que.pop();num++;if (node->left) que.push(node->left); // 空节点不入队if (node->right) que.push(node->right);}}return num;}
};class Solution2 {
public:int countNodes(TreeNode* root) {return root == NULL ? 0 : countNodes(root->left) + countNodes(root->right) + 1;}
};class Solution3 {
public:// 利用完全二叉树的性质,递归法int countNodes(TreeNode* root) {if (!root) return 0;TreeNode* left = root->left;TreeNode* right = root->right;int Ldepth = 0, Rdepth = 0;while (left) { // 递归左子树left = left->left;Ldepth++;}while (right) { // 递归右子树right = right->right;Rdepth++;}if (Ldepth == Rdepth) {return (2 << Ldepth) - 1; // <<为左移运算符(位运算符),相当于2*leftDepth,但二进制运算计算机算的更快}return countNodes(root->left) + countNodes(root->right) + 1;}
};void my_print(vector <string>& v, string msg)
{cout << msg << endl;for (vector<string>::iterator it = v.begin(); it != v.end(); it++) {cout << *it << " ";}cout << endl;
}void my_print2(vector<vector<int>>& v, string str) {cout << str << endl;for (vector<vector<int>>::iterator vit = v.begin(); vit < v.end(); ++vit) {for (vector<int>::iterator it = (*vit).begin(); it < (*vit).end(); ++it) {cout << *it << ' ';}cout << endl;}
}// 前序遍历迭代法创建二叉树,每次迭代将容器首元素弹出(弹出代码还可以再优化)
void Tree_Generator(vector<string>& t, TreeNode*& node) {if (t[0] == "NULL" || !t.size()) return; // 退出条件else {node = new TreeNode(stoi(t[0].c_str())); // 中t.assign(t.begin() + 1, t.end());Tree_Generator(t, node->left); // 左t.assign(t.begin() + 1, t.end());Tree_Generator(t, node->right); // 右}
}// 层序遍历
vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;if (root != NULL) que.push(root);vector<vector<int>> result;while (!que.empty()) {int size = que.size(); // size必须固定, que.size()是不断变化的vector<int> vec;for (int i = 0; i < size; ++i) {TreeNode* node = que.front();que.pop();vec.push_back(node->val);if (node->left) que.push(node->left); // 空节点不入队if (node->right) que.push(node->right);}result.push_back(vec);}return result;
}int main()
{vector<string> t = { "1", "2", "4", "NULL", "NULL", "5", "NULL", "NULL", "3", "6", "NULL", "NULL", "NULL"}; // 前序遍历my_print(t, "目标树");TreeNode* root = new TreeNode();Tree_Generator(t, root);vector<vector<int>> tree = levelOrder(root);my_print2(tree, "目标树:");Solution2 s1;int result = s1.countNodes(root);cout << "节点数量为:" << result << endl;system("pause");return 0;
}
end
相关文章:

【算法与数据结构】222、LeetCode完全二叉树的节点个数
文章目录 一、题目二、一般遍历解法三、利用完全二叉树性质四、完整代码 所有的LeetCode题解索引,可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、一般遍历解法 思路分析:利用层序遍历,然后用num记录节点数量。其他的例如…...
登录和注册表单的11个HTML最佳实践
原文:11 HTML best practices for login & sign-up forms 原作者:Andrey Sitnik 翻译已获原文作者许可,禁止转载和商用 大多数网站都有登录或注册表单;它们是业务转换的关键部分。然而,即使是流行的站点也没有实现本文中提到的…...
Mysql删除历史数据
Mysql定时删除历史数据 实现 1.创建存储过程(函数) SQL DROP PROCEDURE IF EXISTS KeepDatasWith30Days CREATE PROCEDURE KeepDatasWith30Days() BEGINSELECT maxId:max(Id) FROM tableName WHERE CreateTime<DATE(DATE_SUB(NOW(),INTERVAL 31 D…...

Python—数据结构(一)
先放一张自己学习和整理归纳的思维导图,以便让大家都知道我自己的整体学习路线。 数据结构的学习路上内容枯燥,但坚持下来一定有很大的收获!加油💪🏻! 数据结构 数据的概念数据元素: 若干基本…...
离线环境安装flask依赖包
找到当前版本需要的所有依赖包,生产flask项目生成项目依赖包文件requirements.txt 1)在当前项目目录下 生成requirements文件:pip freeze >requirements.txt 执行requirements文件,安装依赖包:pip install -r requirements.t…...

ChatGPT与Claude对比分析
一 简介 1、ChatGPT: 访问地址:https://chat.openai.com/ 由OpenAI研发,2022年11月发布。基于 transformer 结构的大规模语言模型,包含1750亿参数。训练数据集主要是网页文本,聚焦于流畅的对话交互。对话风格友好,回复通顺灵活,富有创造性。存在一定的安全性问题,可…...

登录和注册页面 - 验证码功能的实现
目录 1. 生成验证码 2. 将本地验证码发布成 URL 3. 后端返回验证码的 URL 给前端 4. 前端将用户输入的验证码传给后端 5. 后端验证验证码 1. 生成验证码 使用hutool 工具生成验证码. 1.1 添加 hutool 验证码依赖 <!-- 验证码 --> <dependency><groupId…...

HDFS的文件块大小(重点)
HDFS 中的文件在物理上是分块存储 (Block ) , 块的大小可以通过配置参数( dfs.blocksize)来规定,默认大小在Hadoop2.x/3.x版本中是128M,1.x版本中是64M。 如果一个文件文件小于128M,该文件会占…...

深度学习(二)
目录 一、神经网络 整体架构: 架构细节: 神经元个数的影响: 神经网络过拟合解决: 卷积网络 整体架构: 卷积层 边缘填充 特征尺寸计算 池化层 特征图变化 递归神经网络 一、神经网络 整体架构: 图中分别为输入层、隐层1、隐层2、输出层 通过输入层输入某数值…...
无涯教程-jQuery - wrapInner( html )方法函数
wrapInner(html)方法使用HTML结构包装每个匹配元素(包括文本节点)的内部子内容。 wrapInner( html ) - 语法 selector.wrapInner( html ) 这是此方法使用的所有参数的描述- html - 将动态创建并环绕目标的HTML字符串。 wrapInner( html ) - 示例 以下是一个简单的示例…...

【unity之IMGUI实践】单例模式管理数据存储【二】
👨💻个人主页:元宇宙-秩沅 👨💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨💻 本文由 秩沅 原创 👨💻 收录于专栏:uni…...

【C++】开源:Linux端ALSA音频处理库
😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍Linux端ALSA音频处理库。 无专精则不能成,无涉猎则不能通。。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,…...

【Linux | Shell】结构化命令2 - test命令、方括号测试条件、case命令
目录 一、概述二、test 命令2.1 test 命令2.2 方括号测试条件2.3 test 命令和测试条件可以判断的 3 类条件2.3.1 数值比较2.3.2 字符串比较 三、复合条件测试四、if-then 的高级特性五、case 命令 一、概述 上篇文章介绍了 if 语句相关知识。但 if 语句只能执行命令,…...

基于单片机的语音识别智能垃圾桶垃圾分类的设计与实现
功能介绍 以51单片机作为主控系统;液晶显示当前信息和状态;通过语音识别模块对当前垃圾种类进行语音识别; 通过蜂鸣器进行声光报警提醒垃圾桶已满;采用舵机控制垃圾桶打开关闭;超声波检测当前垃圾桶满溢程度࿱…...

最新版本docker 设置国内镜像源 加速办法
解决问题:加速 docker 设置国内镜像源 目录: 国内加速地址 修改方法 国内加速地址 1.Docker中国区官方镜像 https://registry.docker-cn.com 2.网易 http://hub-mirror.c.163.com 3.ustc https://docker.mirrors.ustc.edu.cn 4.中国科技大学 https://docker.mirrors…...

深度学习——LSTM解决分类问题
RNN基本介绍 概述 循环神经网络(Recurrent Neural Network,RNN)是一种深度学习模型,主要用于处理序列数据,如文本、语音、时间序列等具有时序关系的数据。 核心思想 RNN的关键思想是引入了循环结构,允许…...

three.js入门二:相机的zoom参数
环境: threejs:129 (在浏览器的控制台下输入: window.__THREE__即可查看版本)vscodewindowedge 透视相机或正交相机都有一个zoom参数,它可以用来将相机排到的内容在canvas上缩放显示。 注意:…...
sql语法树(select)实例
在SELECT节点下,将"*"(表示选择所有列)添加为子节点。下面是一个简单的SQL语句示例: SELECT * FROM customers WHERE age > 25 AND city New York;语法树(Syntax Tree)是由SQL解析器构建的…...

爬虫002_python程序的终端运行_文件运行_ipython的使用---python工作笔记020
用python运行一个文件,就是要写一个.py结尾的文件 然后保存 然后直接cmd中,python 然后写上py文件的路径就可以了 然后看一下内容 看一下终端中运行,直接输入python进入python环境,然后写python代码 回车运行 退出可以用exit()...

智融SW3518S降压协议IC一款适合车充控制芯片
描述 SW3518S 是一款高集成度的多快充协议双口充电芯片, 支持 AC 口任意口快充输出, 支持双口独立限流。 其集成了 5A 高效率同步降压变换器, 支持 PPS/PD/QC/AFC/FCP/SCP/PE/SFCP/VOOC等多种快充协议, 最大输出 PD 100Wÿ…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

ios苹果系统,js 滑动屏幕、锚定无效
现象:window.addEventListener监听touch无效,划不动屏幕,但是代码逻辑都有执行到。 scrollIntoView也无效。 原因:这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作,从而会影响…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...