java数据结构与算法刷题-----LeetCode222. 完全二叉树的节点个数

java数据结构与算法刷题目录(剑指Offer、LeetCode、ACM)-----主目录-----持续更新(进不去说明我没写完):https://blog.csdn.net/grd_java/article/details/123063846

在这里插入图片描述

1. 法一:利用完全二叉树性质,进行递归二分查找

解题思路:时间复杂度O( l o g 2 n log_2{n} log2n),空间复杂度O(n),因为递归底层需要栈来实现
  1. 完全二叉树:除去最后一层,剩下的是满二叉树。其中满二叉树也是完全二叉树的一种。
  1. 完全二叉树最后一层的叶子结点,必须是连续的
  2. 最后一层如果不满,假设最后一层只有一个叶子结点,也一定是左结点。因为它必须连续。所以,缺也不会缺左结点
  1. 满二叉树的结点个数为: 2 高度 − 1 2^{高度}-1 2高度1,例如一个满二叉树高的为5,那么一共有 2 5 − 1 = 31 2^5-1 = 31 251=31个结点
  2. 所以,我们依次从根节点开始遍历
  1. 如果当前结点代表着一棵满二叉树(完全二叉树前提下,左子树高的 = 右子树高度),那么代表左子树一定是满的。而右子树未必是满的,因为只是高度一样,完全二叉树只能保证,缺也不会缺左结点。而现在有右节点,说明左节点不缺
  2. 因此左子树高的 = 右子树高度,可以直接跳过左子树,用公式 2 左子树高度 − 1 2^{左子树高度}-1 2左子树高度1计算左子树的结点个数,然后算上当前根节点+1,最终为 2 左子树高度 2^{左子树高度} 2左子树高度个结点
  3. 但是如果左子树高的 != 右子树高度,说明最后一层不满,但是除去最后一层,其余的一定为满二叉树,所以右子树一定是满二叉树,只不过比左子树高的少1而已
  4. 因此左子树高的 != 右子树高度时:右子树的结点个数+当前结点 = 2 右子树高度 2^{右子树高度} 2右子树高度
代码

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */

class Solution {
    /**
        left == right。表示左右子树深度相同,又因为是完全二叉树,因为节点已经填充到右子树了
        所以左子树一定是满二叉树,所以左子树的节点总数是 2^left - 1,加上当前这个 root 节点,则正好是 2^left(2的left次方)。
        然后只需要再对右子树进行递归统计即可。
        left != right。表示左右子树深度并不一致,因为是完全二叉树,必然是左深右浅
        而且最后一层是不满的,倒数第二层必然是满的,而左深右浅,说明右子树是满二叉树,它的深度比左子树少1。为2^right
        那么也同样进行,右子树节点 + root 节点,总数为 2^right。再对左子树进行递归查找。
        
        其中2的多少多少次方,可以写为 1 << 多少多少。例如 1 << left等价于2^left(2的left次方)
     */
    public int countNodes(TreeNode root) {
        if(root == null) return 0;//如果是空树直接返回0
        int left = countLevel(root.left);//获取左子树的深度
        int right = countLevel(root.right);//获取右子树的深度
        //如果左子树深度和右子树一致,就说明root的子树是满二叉树
        if(left == right)//如果是满二叉树,它的最后一个叶子结点一定在最右边侧
            return countNodes(root.right) + (1 << left);//所以疯狂递归统计右边结点,另外不要忘记加上左子树的结点
        else//如果不是满二叉树,那么对完全二叉树来说,它的最后一个叶子结点一定在左侧
            return countNodes(root.left) + (1 << right);//所以疯狂遍历左边,另外不要忘记加上右子树结点
    }
    //统计root结点的深度
    private int countLevel(TreeNode root){
        int level = 0;
        //只统计左子树,因为是完全二叉树的原因,无论是否为满二叉树,哪怕是它的最后一层只有一个叶子结点
        //也一定落在左侧。
        while(root != null){
            level++;
            root = root.left;//每向下走一次,level + 1 一下
        }
        return level;
    }
}

2. 二分查找+位运算

解题思路:时间复杂度O( l o g 2 n log_2{n} log2n),空间复杂度O(1)
  1. 先统计深度
  2. 那么倒数第二层必然是满二叉树。
  3. 最后一层不确定有多少个
  4. 我们对其进行二分查找。看看最后一个叶子结点,在最后一层哪个位置
  5. 最后将倒数第二层的满二叉树+最后一层的结点个数 = 整个数的结点个数
代码

在这里插入图片描述

class Solution {
    public int countNodes(TreeNode root) {
        if (root == null) {//如果root为null直接返回
            return 0;
        }
        int level = 0;//保存高度(深度)
        TreeNode node = root;//获取当前结点
        while (node.left != null) {//如果左节点存在
            level++;//统计深度
            node = node.left;
        }
        //low表示左后一层最左边的结点。
        //因为我们从0开始统计的level,所以1 << level -1(2^level-1)正好是倒数第二层的满二叉树结点
        //high 表示 如果是满二叉树,它为最后一个结点
        //我们在这个范围进行二分查找
        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 k) {
        int bits = 1 << (level - 1);//bits指向倒数第二层
        TreeNode node = root;
        while (node != null && bits > 0) {
            if ((bits & k) == 0) {
                node = node.left;
            } else {
                node = node.right;
            }
            bits >>= 1;
        }
        return node != null;
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

145. Binary Tree Postorder Traversal(二叉树的后序遍历)

问题描述 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 问题分析 此问题与二叉树的前序遍历分析类似&#xff0c;只是在数组合并的时候顺序发生一下变化就行了。 代码 int* postorderTraversal(struct TreeNode* root, int* returnSize) {if(root…

【电子书】计算机课程

资料 wx&#xff1a;1945423050 个人整理了一些互联网电子书 计算机课程 Netty权威指南&#xff08;第2版&#xff09;.epubSharePoint Server 2016 IT Pro 部署指南.epubTensorFlow自然语言处理.epubWebGIS之OpenLayers全面解析.epub从Paxos到Zookeeper分布式一致性原理与实践…

《图解设计模式》笔记(一)适应设计模式

图灵社区 - 图解设计模式 - 随书下载 评论区 雨帆 2017-01-11 16:14:04 对于设计模式&#xff0c;我个人认为&#xff0c;其实代码和设计原则才是最好的老师。理解了 SOLID&#xff0c;如何 SOLID&#xff0c;自然而然地就用起来设计模式了。Github 上有一个 tdd-training&…

Javascript中var和let之间的区别

文章目录 一.变量提升(声)二.let和var的区别 区别&#xff1a; 1、var有变量提升&#xff0c;而let没有&#xff1b; 2、let不允许在相同的作用域下重复声明&#xff0c;而var允许&#xff1b; 3、let没有暂时性死区问题&#xff1b; 4、let创建的全局变量没有给window设置对应…

【广度优先搜索】【网格】【割点】【 推荐】1263. 推箱子

作者推荐 视频算法专题 涉及知识点 广度优先搜索 网格 割点 并集查找 LeetCode:1263. 推箱子 「推箱子」是一款风靡全球的益智小游戏&#xff0c;玩家需要将箱子推到仓库中的目标位置。 游戏地图用大小为 m x n 的网格 grid 表示&#xff0c;其中每个元素可以是墙、地板或…

ctfshow web入门 web141-145

1.web141 ^\w$表示在开头和末尾匹配字母数字_&#xff0c;传入的v3值不能有字母数字_&#xff0c;即无字母的命令执行 php中1-phpinfo()是可以执行的&#xff0c;加减乘除都可以实现 这里或&#xff0c;异或&#xff0c;取反等运算都可以 这里采用羽师傅的异或脚本生成paylo…

小白水平理解面试经典题目LeetCode 404 Sum of Left Leaves【Tree】

404 左叶之和 小白翻译 给定二叉树的root&#xff0c;返回所有左叶的总和。 叶子是没有子节点的节点。左叶是另一个节点的左子节点的叶。 例子 小白教室做题 在大学某个自习的下午&#xff0c;小白坐在教室看到这道题。想想自己曾经和白月光做题&#xff0c;现在大过年的&a…

[服务器-数据库]MongoDBv7.0.4不支持ipv6访问

文章目录 MongoDBv7.0.4不支持ipv6访问错误描述问题分析错误原因解决方式 MongoDBv7.0.4不支持ipv6访问 错误描述 报错如下描述 Cannot connect to MongoDB.No suitable servers found: serverSelectionTimeoutMS expired: [failed to resolve 2408]问题分析 首先确定其是…

Github 2024-02-22 开源项目日报 Top10

根据Github Trendings的统计&#xff0c;今日(2024-02-22统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目4非开发语言项目2Go项目2HTML项目1Dart项目1Vue项目1JavaScript项目1TypeScript项目1 《Hello 算法…

Docker镜像加速

前言 众所周知&#xff0c;我们常用的一些工具或系统的下载源都是国外的&#xff0c;这就会导致我们在下载一些东西时&#xff0c;会导致下载巨慢或者下载失败的情况&#xff0c;下面便是docker换下载源的教程 镜像加速 下面是几个常用的国内的镜像 科大镜像&#xff1a;ht…

ARMv8-AArch64 的异常处理模型详解之异常处理详解(进入异常以及异常路由)

在上篇文章 ARMv8-AArch64 的异常处理模型详解之异常处理概述Handling exceptions中&#xff0c;作者对异常处理整体流程以及相关概念做了梳理。接下来&#xff0c;本文将详细介绍处理器在获取异常、异常处理以及异常返回等过程中都做了哪些工作。 ARMv8-AArch64 的异常处理模型…

深度学习系列60: 大模型文本理解和生成概述

参考网络课程&#xff1a;https://www.bilibili.com/video/BV1UG411p7zv/?p98&spm_id_frompageDriver&vd_source3eeaf9c562508b013fa950114d4b0990 1. 概述 包含理解和分类两大类问题&#xff0c;对应的就是BERT和GPT两大类模型&#xff1b;而交叉领域则对应T5 2.…

C++ 之LeetCode刷题记录(三十三)

&#x1f604;&#x1f60a;&#x1f606;&#x1f603;&#x1f604;&#x1f60a;&#x1f606;&#x1f603; 开始cpp刷题之旅。 目标&#xff1a;执行用时击败90%以上使用 C 的用户。 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;…

贝叶斯统计——入门级笔记

绪论 1.1 引言 全概率公式 贝叶斯公式 三种信息 总体信息 当把样本视为随机变量时&#xff0c;它有概率分布&#xff0c;称为总体分布&#xff0e; 如果我们已经知道总体的分布形式这就给了我们一种信息&#xff0c;称为总体信息 样本信息 从总体中抽取的样本所提供的信息 先…

无人机的视频图传技术

在操控无人机时&#xff0c;视频图传技术显得尤为关键。通过这项技术&#xff0c;无人机的摄像头所捕捉的画面能实时回传至遥控器&#xff0c;使操作者全面掌握无人机的拍摄情况。同时&#xff0c;无人机图传技术也是衡量无人机性能的重要标准&#xff0c;它关乎飞行距离与时间…

先进语言模型带来的变革与潜力

用户可以通过询问或交互方式与GPT-4这样的先进语言模型互动&#xff0c;开启通往知识宝库的大门&#xff0c;即时访问人类历史积累的知识、经验与智慧。像GPT-4这样的先进语言模型&#xff0c;能够将人类历史上积累的海量知识和经验整合并加以利用。通过深度学习和大规模数据训…

C#,动态规划(DP)丢鸡蛋问题(Egg Dropping Puzzle)的三种算法与源代码

1 扔鸡蛋问题 动态规划&#xff08;Dynamic Programming&#xff0c;DP&#xff09;是运筹学的一个分支&#xff0c;是求解决策过程最优化的过程。20世纪50年代初&#xff0c;美国数学家贝尔曼&#xff08;R.Bellman&#xff09;等人在研究多阶段决策过程的优化问题时&#xf…

【云原生】持续集成持续部署

本文主要总结CI/CD的流程&#xff0c;不会详细介绍每个知识点。 啥是集成&#xff1f;啥是部署&#xff1f; 集成&#xff0c;就是把应用程序、相关环境、配置全局打包放在一个容器中的操作。部署就不解释了。 CI/CD 如果是自己手动部署的话&#xff0c;流程应该是这样的&am…

亿道丨三防平板电脑厂家丨三防平板PDA丨三防工业平板:数字时代

在当今数字化时代&#xff0c;我们身边的世界变得越来越依赖于智能设备和无线连接。其中&#xff0c;三防平板PDA&#xff08;Personal Digital Assistant&#xff09;作为一种功能强大且耐用的数字工具&#xff0c;正在引领我们进入数字世界的全新征程。 三防平板PDA结合了平板…

深度学习系列59:文字识别

1. 简单文本&#xff1a; 使用google加的tesseract&#xff0c;效果不错。 首先安装tesseract&#xff0c;在mac直接brew install即可。 python调用代码&#xff1a; import pytesseract from PIL import Image img Image.open(1.png) pytesseract.image_to_string(img, lan…