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

news2024/10/6 7:23:22

题目链接

题目描述

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

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

示例 1:
在这里插入图片描述

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

输入:root = []
输出:0
示例 3:

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

解题思路

作为一个菜鸟,当然直接反手一个dfs遍历,提交,over

代码

class Solution {
    public int countNodes(TreeNode root) {
        return dfs(root);
    }

    public int dfs(TreeNode root){
        if(root == null){
            return 0;
        }
        return dfs(root.left) + dfs(root.right) + 1;
    }
}

解题思路二

当然,拿来写题解了,说明这道题目不是如此的简单,如果只是按照dfs或者bfs来解题,代码固然简单,但是时间复杂度是O(N), 不是最优的。
下面介绍O(logn^2)的时间复杂度解法:

通过二分查找+位运算可以将时间复杂度优化

因为题目中明确的告诉你了这是一颗完全二叉树,所以,要利用好完全二叉树的性质。
完全二叉树第i层最多有 2 i 2^i 2i个节点,最下面的一层节点个数最少为1,最多为 2 i 2^i 2i,所以,只有最下面一层的节点个数是不确定的,但是我们可以根据二叉树的层数确定最少和最大的范围:

  • 当最底层包含 1个节点时,完全二叉树的节点个数是: 2 h 2^h 2h

  • 当最底层包含 2 h 2^h 2h个节点时,完全二叉树的节点个数是: 2 h + 1 − 1 2^{h+1} - 1 2h+11

可以在该范围内通过二分查找的方式得到完全二叉树的节点个数。

具体做法是,根据节点个数范围的上下界,确定当前要判断的节点个数mid,假如mid存在,那说明节点个数比mid多,在后一半搜索,如果,mid不存在,说明节点个数比mid少,在前一半搜索。

那么如何确定mid这个数是否在二叉树中存在呢?技巧是使用位运算。
联想一下我们构造哈夫曼树的办法,我们构造哈夫曼树的时候使用0和1表示向左向右,这里同样可以。

看这个例子

    1            h = 0
   / \
  2   3          h = 1
 / \  /
4  5 6           h = 2

现在这个树中的值都是节点的编号,最底下的一层的编号是 [ 2 h , 2 h + 1 − 1 ] [2^h, 2^{h+1}-1] [2h,2h+11],现在h=2,也就是4,5,6,7对应二进制分别为 100 101 110 111。不看最左边的1,从第二位开始,0表示向左,1表示向右,正好可以表示这个节点相对于根节点的位置。

那么想访问最后一层的节点就可以从节点的编号的二进制入手。从第二位开始的二进制位表示了最后一层的节点相对于根节点的位置。

那么就需要一个bits = 2 h − 1 2^{h-1} 2h1,上面例子中的bits就是2,对应二进制为010。这样就可以从第二位开始判断。(树三层高,需要向左或向右走两次才能到叶子)

比如看5这个节点存不存在,先通过位运算找到编号为5的节点相对于根节点的位置。010 & 101 发现第二位是0,说明从根节点开始,第一步向左走。

之后将bit右移一位,变成001。001 & 101 发现第三位是1,那么第二步向右走。

最后bit为0,说明已经找到编号为5的这个节点相对于根节点的位置,在看这个节点是不是空,不是空说明存在,exist返回真

若编号为5的节点存在,说明总节点数量一定大于等于5。所以二分那里low = mid

再比如看7存不存在,010 & 111 第二位为1,第一部从根节点向右;001 & 111 第三位也为1,第二步继续向右。

然后判断当前节点是不是null,发现是null,exist返回假。

编号为7的节点不存在,说明总节点数量一定小于7。所以high = mid - 1。

解题代码二

class Solution{
    public int countNodes(TreeNode root){
        if(root == null){
            return 0;
        }
        int level = 0;  // 统计多少层
        TreeNode node = root;
        while(node.left != null){
            // 走最左侧的边,能找到最大深度
            level++;
            node = node.left;
        }
        // 确定节点个数的上下界
        int low = 1<<level,high = (1<<(level+1)) - 1;
        while(low < high){
            int mid = (high - low + 1) / 2 + low;
            if(exists(root,level,mid)){
                low = mid;
            }else{
                high = mid- 1;
            }
        }
        return low;
    }

    public boolean exists(TreeNode root, int level, int mid){
        int bits = 1 << (level - 1);   // 需要把bits个位置逐一判断
        TreeNode node = root;
        while(node != null && bits > 0){
            if((mid & bits) == 0){ // 如果这一层是0,向左走
                node = node.left;
            }else{
                node = node.right;  // 是1向右走
            }
            bits >>= 1; // 判断右侧一位是1还是0
        }
        return node != null;  // 如果走到的这个位置是null,说明节点不存在,不是null,说明节点存在
    }
}

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

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

相关文章

vue2—— mixin 超级详细!!!

mixin Mixin是面向对象程序设计语言中的类&#xff0c;提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类 Mixin类通常作为功能模块使用&#xff0c;在需要该功能时“混入”&#xff0c;有利于代码复用又避免了多继承的复杂 vue中的mixin 先来看一下官方定义 mi…

【麒麟(Linux)系统远程连接到windows系统并进行文件传输】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言使用步骤总结 前言 一般来说&#xff0c;windows自带远程桌面&#xff0c;使用的RDP协议&#xff0c;Linux上支持RDP协议的软件很多&#xff0c;常用的是Remmi…

基于决策树的DDoS攻击检测与防护系统研究---实验/论文

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计3077字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

【前端热门框架【vue框架】】——条件渲染和列表渲染的学习的秒杀方式

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;程序员-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;v…

HTTPS证书申请:相关流程及注意事项

申请HTTPS证书的过程主要包括以下几个步骤&#xff0c;以及一些需要注意的事项&#xff1a; 申请流程&#xff1a; 1. 选择证书类型和期限&#xff1a; - 根据需求选择合适的SSL证书类型&#xff0c;常见的有DV&#xff08;域名验证&#xff09;、OV&#xff08;组织验证&#…

Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理

Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理 目录 Unity 问题之 开发应用在设备上运行闪屏花屏问题的分析处理 一、简单介绍 二、问题现象 三、问题分析 四、使用空后处理&#xff0c;解决闪屏花屏的显示问题 五、空后处理完整代码 一、简单介绍 Unity 在…

鸿蒙开发HarmonyOS4.0入门与实践

鸿蒙开发HarmonyOS4.0 配合视频一起食用&#xff0c;效果更佳 课程地址&#xff1a;https://www.bilibili.com/video/BV1Sa4y1Z7B1/ 源码地址&#xff1a;https://gitee.com/szxio/harmonyOS4 准备工作 官网地址 鸿蒙开发者官网&#xff1a;https://developer.huawei.com/con…

使用FPGA发送一个经过曼彻斯特编码的伪随机序列

介绍 这几天突然就不知道要使用FPGA实现什么样的功能了,然后就跑去学习数电了,学的也是晕晕的。正好之前写了一个使用FPGA发送伪随机序列的代码,然后因为需要使用曼彻斯特编码,所以又加了一个模块吧,使得最后输出的波形经过曼彻斯特编码。 曼彻斯特编码 首先,曼彻斯特编…

【操作系统复习资料】(持续更新中)

目录 第一章&#xff1a;操作系统引论 第二章&#xff1a;进程的描述与控制 未完待续。。。。。接 第三章&#xff1a;处理机调度与死锁 第四章&#xff1a;存储器管理 第五章&#xff1a;虚拟存储器 第六章&#xff1a;第八节 磁盘存储器的性能和调度 第一章&#xff1a…

pgvector扩展在IvorySQL Oracle兼容模式下的应用实践

向量数据库是生成式人工智能(GenAI)的关键组成部分。作为PostgreSQL的重要扩展&#xff0c;pgvector支持高达16000维的向量计算能力&#xff0c;使得PostgreSQL能够直接转化为高效的向量数据库。 IvorySQL基于PostgreSQL开发&#xff0c;因此它同样支持添加pgvector扩展。在Ora…

社交媒体数据恢复:新浪微博

当我们在使用新浪微博时&#xff0c;可能会遇到一些意外情况&#xff0c;如误删微博、账号出现问题等。这时&#xff0c;我们需要进行数据恢复。本文将详细介绍如何在新浪微博中进行数据恢复。 首先&#xff0c;我们需要了解新浪微博的数据恢复功能。根据微博的帮助中心&#…

实验8 顺序图、状态图

一、实验目的 通过绘制顺序图、状态图&#xff0c;掌握顺序图、状态图之间的基本原理和差异。 能对简单问题进行顺序图、状态图的分析与绘制。 二、实验项目内容&#xff08;实验题目&#xff09; 在图书信息管理系统中&#xff0c;系统管理员可以对图书信息进行管理和维护…

Python轻量级Web框架Flask(12)—— Flask类视图实现前后端分离

0、前言&#xff1a; 在学习类视图之前要了解前后端分离的概念&#xff0c;相对于之前的模板&#xff0c;前后端分离的模板会去除views文件&#xff0c;添加两个新python文件apis和urls&#xff0c;其中apis是用于传输数据和解析数据 的&#xff0c;urls是用于写模板路径的。 …

merge and rebase

文章目录 什么是merge什么是rebasemerge和rebase的区别操作执行git merge操作git rebase操作冲突解决解决冲突的步骤 Git Merge 和 Git Rebase 都是用于集成来自不同分支的修改的 Git 命令。 什么是merge Git Merge 是将一个分支的改动合并到另一个分支的方式。当你执行一个 m…

Unity 物体触碰事件监听

声明委托 public delegate void MyDelegate(Collider trigger); C# 委托&#xff08;Delegate&#xff09; | 菜鸟教程 (runoob.com)https://www.runoob.com/csharp/csharp-delegate.html 定义委托 public MyDelegate onTriggerEnter; public MyDelegate onTriggerStay; pu…

Leetcode—1041. 困于环中的机器人【中等】

2024每日刷题&#xff08;121&#xff09; Leetcode—1041. 困于环中的机器人 实现代码 class Solution { public:bool isRobotBounded(string instructions) {int x 0;int y 0;int d 0;vector<vector<int>> direction{{0, 1}, {1, 0}, {0, -1}, {-1, 0}};for…

C语言阶段的题目解析

前言 我们C语言已经学习的差不多了&#xff0c;但是C语言之中存在的一些问题与难点我们还不一定能够又快又好地解决&#xff0c;为了夯实我们的基础&#xff0c;我们来练习几道稍微有点难度的C语言习题吧 例题一 题目 int main(void) {unsigned char i 7;int j 0;for (; i…

织梦云端:网络信号原理的艺术解码

hello &#xff01;大家好呀&#xff01; 欢迎大家来到我的Linux高性能服务器编程系列之《织梦云端&#xff1a;网络信号原理的艺术解码》&#xff0c;在这篇文章中&#xff0c;你将会学习到网络信号原理以及应用&#xff0c;并且我会给出源码进行剖析&#xff0c;以及手绘UML图…

MQTT数据传输Payload的常见格式介绍

使用MQTT client过程中看到常见的数据格式&#xff1a; 下面是介绍 Plaintext&#xff08;纯文本&#xff09; 介绍&#xff1a;纯文本编码是最基本的编码形式&#xff0c;它使用标准的ASCII或Unicode字符来表示数据。这种编码格式是人类可读的&#xff0c;因为它直接表示文本信…

centos 7使用源码编译安装Python 3.12.2(最新版本)

&#xff08;一&#xff09;、说明 在centos 7上&#xff0c;默认安装出来的python是&#xff1a;2.7.5版本 1.查看python版本&#xff1a; python --version 2.通过yum安装出来的&#xff0c;适合当前操作系统的&#xff0c;最新的python版本是&#xff1a;3.6.8 python3…