【C++代码】二叉树的最大深度,二叉树的最小深度,完全二叉树的节点个数--代码随想录

news2024/11/27 20:58:16

题目:二叉树的最大深度

  • 给定一个二叉树 root ,返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
题解
  • 如果我们知道了左子树和右子树的最大深度 l 和 r,那么该二叉树的最大深度即为 m a x ( l , r ) + 1 max(l,r)+1 max(l,r)+1 。而左子树和右子树的最大深度又可以以同样的方式进行计算。因此我们可以用「深度优先搜索」的方法来计算二叉树的最大深度。具体而言,在计算当前二叉树的最大深度时,可以先递归计算出其左子树和右子树的最大深度,然后在 O(1) 时间内计算出当前二叉树的最大深度。递归在访问到空节点时退出。

  • /**
     * 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 maxDepth(TreeNode* root) {
            if(root==nullptr)
            return 0;
            return max(maxDepth(root->left),maxDepth(root->right))+1;
        }
    };
    
  • 时间复杂度:O(n),其中 n 为二叉树节点的个数。每个节点在递归中只被遍历一次。空间复杂度:O(height),其中 height 表示二叉树的高度。递归函数需要栈空间,而栈空间取决于递归的深度,因此空间复杂度等价于二叉树的高度。

  • 广度优先搜索

    • 用「广度优先搜索」的方法来解决这道题目,但我们需要对其进行一些修改,此时我们广度优先搜索的队列里存放的是「当前层的所有节点」。每次拓展下一层的时候,不同于广度优先搜索的每次只从队列里拿出一个节点,我们需要将队列里的所有节点都拿出来进行拓展,这样能保证每次拓展完的时候队列里存放的是当前层的所有节点,即我们是一层一层地进行拓展,最后我们用一个变量 ans 来维护拓展的次数,该二叉树的最大深度即为 ans。

    • class Solution {
      public:
          int maxDepth(TreeNode* root) {
              if(root==nullptr)
              return 0;
              // return max(maxDepth(root->left),maxDepth(root->right))+1;
              queue<TreeNode*> temp_que;
              temp_que.push(root);
              int ans = 0;
              while(!temp_que.empty()){
                  int sz = temp_que.size();
                  // cout<<sz<<endl;
                  while(sz>0){
                      TreeNode* node=temp_que.front();
                      temp_que.pop();
                      if(node->left){
                          temp_que.push(node->left);
                      }
                      if(node->right){
                          temp_que.push(node->right);
                      }
                      sz-=1;
                  }
                  ans+=1;
              }
              return ans;
          }
      };
      

题目:二叉树的最小深度

  • 给定一个二叉树,找出其最小深度。最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
题解
  • 首先可以想到使用深度优先搜索的方法,遍历整棵树,记录最小深度。对于每一个非叶子节点,我们只需要分别计算其左右子树的最小叶子节点深度。这样就将一个大问题转化为了小问题,可以递归地解决该问题。

  • /**
     * 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 minDepth(TreeNode* root) {
            if(root==nullptr){
                return 0;
            }
            if(root->left==nullptr&&root->right==nullptr){
                return 1;
            }
            int min_depth=INT_MAX;
            if(root->left!=nullptr){
                min_depth=min(minDepth(root->left),min_depth);
            }
            if(root->right!=nullptr){
                min_depth=min(minDepth(root->right),min_depth);
            }
            return min_depth+1;
        }
    };
    
  • 时间复杂度:O(N),其中 N 是树的节点数。对每个节点访问一次。空间复杂度:O(H),其中 H 是树的高度。空间复杂度主要取决于递归时栈空间的开销,最坏情况下,树呈现链状,空间复杂度为 O(N)。平均情况下树的高度与节点数的对数正相关,空间复杂度为 O(log⁡N)。

  • 广度优先搜索

    • 当我们找到一个叶子节点时,直接返回这个叶子节点的深度。广度优先搜索的性质保证了最先搜索到的叶子节点的深度一定最小

    • class Solution {
      public:
          int minDepth(TreeNode* root) {
              if(root==nullptr){
                  return 0;
              }
              queue<pair<TreeNode *,int>> temp_que;
              temp_que.emplace(root,1);
              while(!temp_que.empty()){
                  TreeNode *temp_node = temp_que.front().first;
                  int depth = temp_que.front().second;
                  temp_que.pop();
                  if(temp_node->left==nullptr&&temp_node->right==nullptr){
                      return depth;
                  }
                  if(temp_node->left!=nullptr){
                      temp_que.emplace(temp_node->left,depth+1);
                  }
                  if(temp_node->right!=nullptr){
                      temp_que.emplace(temp_node->right,depth+1);
                  }
              }
              return 0;
          }
      };
      
    • 时间复杂度:O(N),其中 N 是树的节点数。对每个节点访问一次。空间复杂度:O(N),其中 N 是树的节点数。空间复杂度主要取决于队列的开销,队列中的元素个数不会超过树的节点数

题目:完全二叉树的节点个数

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

    • 在这里插入图片描述
题解
  • 深度优先遍历数的所有节点,不过没有使用到完全二叉树的性质。时间复杂度为 O(n),空间复杂度为 O(1)【不考虑递归调用栈】

  • class Solution {
    public:
        int countNodes(TreeNode* root) {
            int count=0;
            if(root==nullptr){
                return 0;
            }
            int left=countNodes(root->left);
            int right=countNodes(root->right);
            return left+right+1;
        }
    };
    
  • 确定递归函数的参数和返回值:参数就是传入树的根节点,返回就返回以该节点为根节点二叉树的节点数量,所以返回值为int类型。确定终止条件:如果为空节点的话,就返回0,表示节点数为0。确定单层递归的逻辑:先求它的左子树的节点数量,再求右子树的节点数量,最后取总和再加一 (加1是因为算上当前中间节点)就是目前节点为根节点的节点数量

  • 对于任意二叉树,都可以通过广度优先搜索或深度优先搜索计算节点个数,时间复杂度和空间复杂度都是 O(n),其中 n 是二叉树的节点个数。这道题规定了给出的是完全二叉树,因此可以利用完全二叉树的特性计算节点个数。规定根节点位于第 0 层,完全二叉树的最大层数为 h。根据完全二叉树的特性可知,完全二叉树的最左边的节点一定位于最底层,因此从根节点出发,每次访问左子节点,直到遇到叶子节点,该叶子节点即为完全二叉树的最左边的节点,经过的路径长度即为最大层数 h。当 0 ≤ i < h 0≤i<h 0i<h 时,第 i 层包含 2 i 2^i 2i个节点,最底层包含的节点数最少为 1,最多为 2 h 2^h 2h

    • 当最底层包含 1 个节点时,完全二叉树的节点个数是 ∑ i = 0 h − 1 2 i + 1 = 2 h \sum_{i=0}^{h-1}2^i+1=2^h i=0h12i+1=2h;

    • 当最底层包含 2 h 2^h 2h 个节点时,完全二叉树的节点个数是 ∑ i = 0 h 2 i = 2 h + 1 − 1 \sum_{i=0}^{h}2^i=2^{h+1}-1 i=0h2i=2h+11

  • 因此对于最大层数为 h 的完全二叉树,节点个数一定在 [ 2 h , 2 h + 1 − 1 ] [2^h,2^{h+1}-1] [2h,2h+11] 的范围内,可以在该范围内通过二分查找的方式得到完全二叉树的节点个数。具体做法是,根据节点个数范围的上下界得到当前需要判断的节点个数 k,如果第 k 个节点存在,则节点个数一定大于或等于 k,如果第 k 个节点不存在,则节点个数一定小于 k,由此可以将查找的范围缩小一半,直到得到节点个数

  • 在这里插入图片描述

  • 如何判断第 k 个节点是否存在呢?如果第 k 个节点位于第 h 层,则 k 的二进制表示包含 h+1 位,其中最高位是 1,其余各位从高到低表示从根节点到第 k 个节点的路径,0 表示移动到左子节点,1 表示移动到右子节点。通过位运算得到第 k 个节点对应的路径,判断该路径对应的节点是否存在,即可判断第 k 个节点是否存在。222. 完全二叉树的节点个数 - 力扣(LeetCode)

  • class Solution {
    public:
        bool exists(TreeNode *root,int high,int k){
            int bits=1<<(high-1);
            TreeNode* node =root;
            while(node!=nullptr&&bits>0){
                if(!(bits&k)){
                    node=node->left;
                }else{
                    node=node->right;
                }
                bits>>=1;
            }
            return node!=nullptr;
        }
        int countNodes(TreeNode* root) {
            if(root==nullptr){
                return 0;
            }
            // int left=countNodes(root->left);
            // int right=countNodes(root->right);
            // return left+right+1;
            int high=0;
            TreeNode *node = root;
            while(node->left!=nullptr){
                high++;
                node = node->left;
            }
            int min_count=1<<high,max_count=(1<<(high+1))-1;
            while(min_count<max_count){
                int mid=(max_count-min_count+1)/2+min_count;
                if(exists(root,high,mid)){
                    min_count=mid;
                }else{
                    max_count=mid-1;
                }
            }
            return min_count;
        }
    };
    
  • 时间复杂度: O ( log ⁡ 2 n ) O(\log^2 n) O(log2n),其中 n 是完全二叉树的节点数。 首先需要 O(h) 的时间得到完全二叉树的最大层数,其中 h 是完全二叉树的最大层数。 使用二分查找确定节点个数时,需要查找的次数为 O ( log ⁡ 2 h ) = O ( h ) O(\log 2^h)=O(h) O(log2h)=O(h),每次查找需要遍历从根节点开始的一条长度为 h 的路径,需要 O(h) 的时间,因此二分查找的总时间复杂度是 O ( h 2 ) O(h^2) O(h2)。 因此总时间复杂度是 O ( h 2 O(h^2 O(h2。由于完全二叉树满足 2 h ≤ n < 2 h + 1 2^h \le n < 2^{h+1} 2hn<2h+1,因此有 O ( h ) = O ( log ⁡ n ) O(h)=O(\log n) O(h)=O(logn) O ( h 2 ) = O ( log ⁡ 2 n ) O(h^2)=O(\log^2 n) O(h2)=O(log2n)。空间复杂度:O(1)。只需要维护有限的额外空间。

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

    • 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;
      

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

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

相关文章

令人惊艳的AI项目,这也太猛了...

大家好&#xff0c;我是 Jack。 这两天&#xff0c;我在网上冲浪&#xff0c;发现了一款神器&#xff01; 我在使用 AI 绘画 Stable Diffsuion 和 Midjourney 的时候&#xff0c;花费时间最多的就是写 prompt 描述词了&#xff0c;绞尽脑汁地调试 prompt。 同样&#xff0c;…

pdf怎么转换成word?推荐这几种方法

pdf怎么转换成word&#xff1f;pdf转换成Word是一项常见的需求&#xff0c;首先&#xff0c;Word文档是一种常用的文档格式&#xff0c;几乎在任何计算机上都可以打开和编辑。与PDF相比&#xff0c;Word文档更加灵活和可编辑&#xff0c;可以轻松地修改和更新文档内容。在使用这…

macOS文件差异比较最佳工具:Beyond Compare 4

Beyond Compare for mac是一款Scooter Software研发的文件同步对比工具。你可以选择针对多字节的文本、文件夹、源代码&#xff0c;甚至是支持比对adobe文件、pdf文件或是整个驱动器&#xff0c;检查其文件大小、名称、日期等信息。你也可以选择使用Beyond Compare合并两个不同…

《数据结构、算法与应用C++语言描述》使用C++语言实现二维数组下三角矩阵

《数据结构、算法与应用C语言描述》使用C语言实现二维数组下三角矩阵 下三角矩阵定义 如下图所示&#xff1a; 代码实现 _11lowerTriangularMatrix.h 模板类 /* Project name : allAlgorithmsTest Last modified Date: 2022年8月13日17点38分 Last Version: V1.0 D…

Linux-文件和目录权限

文章目录 权限的作用普通文本文件的权限作用 权限的作用 权限对于普通文件和目录文件的作用是不一样的。 普通文本文件的权限作用 drwxr-xr-x第二个字母开始是文件的权限表示9列权限&#xff0c;前三列表示文件的"拥有者"对该文件具有的权限&#xff0c;中三列表…

235. 二叉搜索树的最近公共祖先 Python

文章目录 一、题目描述示例 1示例 2 二、代码三、解题思路 一、题目描述 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公共祖先的定义为&#xff1a;“对于有根树 T 的两个结点 p、q&#xff0c;最近公共祖先表示为一个结点 x&#xff0c;满足…

C++:string的模拟实现

目录 1.string的四大默认函数 1.1构造函数 1.2析构函数 1.3拷贝构造 1.4赋值运算符重载 2.访问string的三种方式 2.1[]访问 2.2迭代器访问 2.3范围for(本质是迭代器) 3.string相关功能的实现 3.1modify 3.2capacity 3.3access 3.4relations 3.5补充 4.补充 1.s…

基于Appium的UI自动化测试

为什么需要UI自动化测试 移动端APP是一个复杂的系统&#xff0c;不同功能之间耦合性很强&#xff0c;很难仅通过单元测试保障整体功能。UI测试是移动应用开发中重要的一环&#xff0c;但是执行速度较慢&#xff0c;有很多重复工作量&#xff0c;为了减少这些工作负担&#xff…

八大排序(二)--------冒泡排序

本专栏内容为&#xff1a;八大排序汇总 通过本专栏的深入学习&#xff0c;你可以了解并掌握八大排序以及相关的排序算法。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;八大排序汇总 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库…

高端知识竞赛中用到的软件和硬件有哪些

现在单位搞知识竞赛&#xff0c;已不满足于用PPT放题&#xff0c;找几个简单的抢答器、计分牌弄一下了&#xff0c;而是对现场效果和科技感要求更高了。大屏要分主屏侧屏&#xff0c;显示内容要求丰富炫酷&#xff1b;选手和评委也要用到平板等设备&#xff1b;计分要大气些&am…

QT在安装后添加新组件【QT基础入门 环境搭建】

一、Qt的安装目录下找到MaintenanceTool工具 二、双击该exe文件运行该工具(界面可能不相同但功能一样) 登录账号,进入以下界面,点击下一步 选择更新组件,出现以下提示 三、此时需要手动添加储存库 1.进入下面网站,选择一个国内镜像 Qt Downloads 点击后面的HTTP可进入…

java CAS详解(深入源码剖析)

CAS是什么 CAS是compare and swap的缩写&#xff0c;即我们所说的比较交换。该操作的作用就是保证数据一致性、操作原子性。 cas是一种基于锁的操作&#xff0c;而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住&#xff0c;等之前获得锁的线程释放锁之后&am…

如何才能实现批量抠图?一键批量抠图的办法

批量抠图是在处理大量图片时非常实用的技术&#xff0c;它可以帮助您快速准确地去除图片的背景或选择特定的对象。在编辑图片和设计时是一项必不可少的技能。 今天分享一款简单方便的抠图工具&#xff0c;智能识别并抠取图片中的各种物体、人物、动物等&#xff0c;效果不错&a…

简单聊聊G1垃圾回收算法整个流程 --- 理论篇 -- 下

简单聊聊G1垃圾回收算法整个流程 --- 理论篇 -- 下 软实时性预测转移时间预测可信度GC 暂停处理的调度并发标记中的暂停处理 分代 G1 GC 模式不同点新生代区域分代对象转移具体转移流程分代选择回收集合设置最大新生代区域数 GC的切换GC执行的时机 总结 上一篇 文章我们简单看了…

JDK新特性-Stream流

Stream流是用来操作集合或者数组中的数据的&#xff0c;Stream流提供了一种更加强大的&#xff0c;更加简单的方式来操作集合或者数组中的数据&#xff0c;代码更加简洁&#xff0c;可读性更好。下面是一个简单的例子&#xff1a; public class S1 {public static void main(S…

12万条中法常见词语对照ACCESS数据库

法文是全球通用的语言之一&#xff0c;要拥有国际视野&#xff0c;学懂全球通用语言是您的必然选择。走向成功之门&#xff0c;尽快学会法文吧。《12万条中法常见词语对照ACCESS数据库》收集了汉语常用词语的法文对照翻译。 本数据库是由 Microsoft Access 2000 创建的 MDB 数据…

算法训练 第三周

一、买卖股票的最佳时机 本题给了我们一个数组&#xff0c;这个数组的第i个元素表示股票第i天的价格&#xff0c;要求我们选择一天买入股票&#xff0c;并在这天之后的某一天卖出&#xff0c;问我们何时能获得最大利润。 1.循环嵌套 我们可以循环遍历所有买入的价格&#xff…

Al中秋节由来

文章目录 简介中秋节的庆祝活动有哪些&#xff1f;有没有其他与中秋节相关的传说或故事&#xff1f; 今天的话题是&#xff0c;扯犊子 简介 中秋节是中国传统的重要节日之一&#xff0c;通常在农历八月十五这一天庆祝。中秋节的由来有多种传说和故事。 其中最有名的传说是关于…

什么是HTTP状态码?常见的HTTP状态码有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是HTTP状态码&#xff1f;⭐ 1xx - 信息性状态码⭐ 2xx - 成功状态码⭐ 3xx - 重定向状态码⭐ 4xx - 客户端错误状态码⭐ 5xx - 服务器错误状态码⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前…

pcl--第五节 点云表面法线估算

估算点云表面法线 * 表面法线是几何表面的重要属性&#xff0c;在许多领域&#xff08;例如计算机图形应用程序&#xff09;中大量使用&#xff0c;以应用正确的光源以产生阴影和其他视觉效果。 给定一个几何表面&#xff0c;通常很难将表面某个点的法线方向推断为垂直于该点…