【算法与数据结构】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] [2K11,2K1]之间,意味着它只有两种情况,一种是满二叉树,一种是最后一层叶子节点没有满。对于情况一可以用 2 K − 1 2^K-1 2K1来计算,对于情况二分别递归其左子树和右子树,递归到一定深度一定有左子树或者右子树为满二叉树,然后按照情况一来计算。那么满二叉树的最左边节点和最右边节点的深度一定是相等的,依据这个特性判断子树是否为满二叉树。
在这里插入图片描述
递归程序当中,我们要确定三个步骤,1、输入参数,返回值 2、递归终止条件 3、单层递归逻辑输入参数为中间节点,返回值为左子树的节点数量+右子树节点数量+1(+1是加上中间节点)。当节点为空时,递归终止,返回0。每次递归我们都要计算最左/右边节点深度,然后判断二者是否相等,如果相等则是满二叉树,返回 2 K − 1 2^K-1 2K1,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

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

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

相关文章

视频增强技术-去噪

本文介绍了关于视频增强技术的相关方法包括传统方法和基于深度学习的方法&#xff0c;并给出了他们的对比实验结果&#xff0c;最后对它们简单的做了总结&#xff0c;文中有一些图片和总结来自于网上其他博主的文章&#xff0c;已在文中标记并给出了相关的原文链接&#xff0c;…

一文掌握如何前后端分离?

随着科技的进步和发展&#xff0c;低代码开发产品拥有广阔的市场前景。前后端分离似乎早已经是发展趋势了&#xff0c;因为做好前后端分离对于前后端的工程师而言是非常有利的&#xff0c;这样也有利于提升办公协作效率。那么&#xff0c;如何前后端分离&#xff1f;分别都有哪…

【机器学习】支持向量机SVM入门

优化目标 相较于之前学习的线性回归和神经网络&#xff0c;支持向量机&#xff08;Supprot Vector Machine&#xff0c;简称SVM&#xff09;在拟合复杂的非线性方程的时候拥有更出色的能力&#xff0c;该算法也是十分经典的算法之一。接下来我们需要学习这种算法 首先我们回顾…

关于Docker的基本概念和使用

关于Docker的基本概念和使用 一、Docker 概述1、Dcker的概念2、容器的优势3、Docker与虚拟机的区别4、容器在内核中支持2种重要技术5、Docker核心概念 二、安装 Docker1、安装依赖包2、设置阿里云镜像源3、安装 Docker-CE并设置为开机自动启动3、查看 docker 版本信息4、docker…

AI智能化技术对项目管理的挑战与应对︱腾讯CSIG能源行业总经理王磊

腾讯CSIG能源行业总经理王磊先生受邀为由PMO评论主办的2023第十二届中国PMO大会演讲嘉宾&#xff0c;演讲议题&#xff1a;AI智能化技术对项目管理的挑战与应对。大会将于8月12-13日在北京举办&#xff0c;敬请关注&#xff01; 议题简要&#xff1a; 自从DALLE、Midjourney、…

linux升级mysql

linux升级mysql 一.介绍二.下载三.文件配置1.查找删除mysql2.解压配置 四.修改配置五.初始化mysql服务六.启动mysql七.配置数据库七.测试 一.介绍 由于最近业务需要&#xff0c;不得不将之前的mysql5.7.26升级到mysql8.0加了 Linux安装mysql&#xff08;5.7.26&#xff09;&…

flask结合mysql实现用户的添加和获取

1、数据库准备 已经安装好数据库&#xff0c;并且创建数据库和表 create database unicom DEFAULT CHARSET utf8 COLLATE utf8_general_ci; CREATE TABLE admin( id int not null auto_increment primary key, username VARCHAR(16) not null, password VARCHAR(64) not null…

初识 Spring (存储和获取 bean)

目录 初识 Spring总结 DI&#xff08;依赖注入&#xff09;Spring 项目的创建创建一个 Maven 项目添加 Spring 框架支持添加启动类 存储 bean 对象创建 bean将 bean 注册到容器中 获取并使用 bean 对象获取 bean 的方法一获取 bean 的方法二获取 bean 的方法三 ApplicationCont…

(Chrome Ext)谷歌扩展程序-谷歌插件渗透测试方法记录

文章目录 前言一、本地获取谷歌插件/扩展程序源码二、工具化信息收集总结 前言 在工作岗位变更之后&#xff0c;越来越多“奇奇怪怪”的东西要去渗透和测试&#xff0c;在我之前干安服的时候&#xff0c;最多的就是测一下web&#xff0c;极少情况下测测app&#xff0c;但是现在…

根据UIL下载图片/视频、根据URL自动下载图片/视频、GUI自动下载想要的图片

1&#xff0c;根据UIL下载图片/视频 def downForInterface(file_path):count 1value_rows []with open(file_path, encodingUTF-8) as file:f_csv csv.reader(file)for r in f_csv:value_rows.append(r)for file_path in value_rows:cunmulu if . in file_path[0]:print(cu…

网页生成PDF表格诡异多出空白

环境&#xff1a; axios: 0.27.0 egg: 2.35.0 pdf-lib: 1.17.1 puppeteer-core: 17.1.3 node: 16.20.0 element-plus: 2.3.2 vue: 3.2.47 背景&#xff1a; 一个报告页面含有多个统计表格和描述文字&#xff0c;生成PDF用于下载查看&#xff0c;页面使用vue3element-plus…

用 Node.js 手写 WebSocket 协议

目录 引言 从 http 到 websocekt 的切换 Sec-WebSocket-Key 与 Sec-WebSocket-Accept 全新的二进制协议 自己实现一个 websocket 服务器 按照协议格式解析收到的Buffer 取出opcode 取出MASK与payload长度 根据mask key读取数据 根据类型处理数据 frame 帧 数据的发…

多种语言示例采集数据【淘宝天猫1688拼多多API系列】可高并发线程

长话短说&#xff0c;节约彼此宝贵时间&#xff0c;我们以淘宝商品详情数据为例&#xff1a; 请求方式&#xff1a;HTTPS POST GET 请求地址&#xff1a;https://o0b.cn/anzexi taobao.item_get 公共参数 名称类型必须描述技术交流18179014480keyString是调用key&#xf…

rust学习-智能指针

适用场景 有一个在编译时未知大小的类型&#xff0c;想在需要确切大小的上下文使用该类型值 示例1 无意义的例子&#xff1a;将一个单独的值存放在堆上并不是很有意义&#xff0c;b更应该放到栈上 fn main() {let b Box::new(5);// box 在 main 的末尾离开作用域时&#x…

[论文阅读笔记24]Social-STGCNN: A Social Spatio-Temporal GCNN for Human Traj. Pred.

论文: 论文地址 代码: 代码地址 作者在这篇文章中直接用GNN对目标的轨迹时空特征进行建模, 并用时序CNN进行预测, 代替了训练难度较大和速度较慢的RNN类方法. 0. Abstract 行人轨迹预测是一个比较有挑战性的任务, 有着许多的应用. 一个行人的轨迹不仅是由自己决定的, 而且受…

产品设计思考:如何平衡用户习惯和用户体验

在产品设计领域&#xff0c;平衡用户习惯与用户体验之间的关系是一个重要而复杂的任务。 用户习惯是指用户在长期使用产品过程中逐渐形成的一种行为模式&#xff0c;而用户体验则是用户在与产品交互时所感受到的整体感受。 在追求良好的用户体验的同时&#xff0c;还需要考虑用…

2023 年第二届钉钉杯大学生大数据挑战赛 初赛 B:美国纽约公共自行车使用量预测分析 问题二Python代码分析

2023 年第二届钉钉杯大学生大数据挑战赛 初赛 B&#xff1a;美国纽约公共自行车使用量预测分析 问题二 相关链接 【2023 年第二届钉钉杯大学生大数据挑战赛】 初赛 B&#xff1a;美国纽约公共自行车使用量预测分析 问题一Python代码分析 【2023 年第二届钉钉杯大学生大数据挑…

进阶级!美创暗数据发现和分类分级系统获中国信通院权威测评

近日&#xff0c;美创科技暗数据发现和分类分级系统顺利通过中国信通院“数据分类分级能力检验进阶级”认证&#xff0c;获颁数据安全产品检验证书。 数据分类分级进阶级评测通过主动探测识别率、被动探测识别率、用户相关数据识别准确率、分级标识准确率等技术指标的检测&…

AMEYA360代理线:ROHM开发出EcoGaN™减少服务器和AC适配器等的损耗和体积!

全球知名半导体制造商ROHM&#xff08;总部位于日本京都市&#xff09;面向数据服务器等工业设备和AC适配器等消费电子设备的一次侧电源*1&#xff0c;开发出集650V GaN HEMT*2和栅极驱动用驱动器等于一体的Power Stage IC“BM3G0xxMUV-LB”&#xff08;BM3G015MUV-LB、BM3G007…

【C++】继承

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…