代码随想录-Day17

110. 平衡二叉树

这道题中的平衡二叉树的定义是:二叉树的每个节点的左右子树的高度差的绝对值不超过 111,则二叉树是平衡二叉树。根据定义,一棵二叉树是平衡二叉树,当且仅当其所有子树也都是平衡二叉树,因此可以使用递归的方式判断二叉树是不是平衡二叉树,递归的顺序可以是自顶向下或者自底向上。

方法一:自顶向下的递归

class Solution {
    public boolean isBalanced(TreeNode root) {
        if (root == null) {
            return true;
        } else {
            return Math.abs(height(root.left) - height(root.right)) <= 1 && isBalanced(root.left) && isBalanced(root.right);
        }
    }

    public int height(TreeNode root) {
        if (root == null) {
            return 0;
        } else {
            return Math.max(height(root.left), height(root.right)) + 1;
        }
    }
}

这段代码是用来检测一棵二叉树是否是平衡二叉树的Java实现。平衡二叉树的定义是:任意两个子树的高度差不大于1。代码中定义了两个方法:isBalancedheight

  • public boolean isBalanced(TreeNode root) 方法是主要的接口,用于判断传入的二叉树根节点 root 所代表的树是否平衡。其逻辑如下:

    • 首先,如果根节点为空,直接返回 true,因为空树被认为是平衡的。
    • 否则,计算左子树和右子树的高度(调用 height 方法),并取两者的高度差的绝对值。如果这个差值小于等于1,并且左子树和右子树也分别都是平衡的(递归调用 isBalanced 方法),则整棵树是平衡的,返回 true;否则,返回 false
  • public int height(TreeNode root) 方法用于计算以 root 为根的二叉树的高度。其逻辑如下:

    • 如果节点为空,高度为0,因为空树的高度定义为0。
    • 否则,递归计算左子树和右子树的高度,并取两者中的较大值,然后加1(因为要算上根节点的高度),作为当前树的高度返回。

综上,这个解决方案通过递归计算每个子树的高度,并在回溯过程中判断树是否满足平衡的条件,最终得出整个二叉树是否平衡的结论。这种方法的时间复杂度最坏情况下是O(n^2),因为每个节点的高度可能被重复计算多次。在实践中,对于极端不平衡的树,性能可能不是最优。有一种优化方法是将高度计算和平衡判断结合起来,只遍历树一次,但这需要更复杂的逻辑来同时跟踪和更新高度信息。

方法二:自底向上的递归

class Solution {
    public boolean isBalanced(TreeNode root) {
        return height(root) >= 0;
    }

    public int height(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftHeight = height(root.left);
        int rightHeight = height(root.right);
        if (leftHeight == -1 || rightHeight == -1 || Math.abs(leftHeight - rightHeight) > 1) {
            return -1;
        } else {
            return Math.max(leftHeight, rightHeight) + 1;
        }
    }
}

这段代码同样是用于判断一棵二叉树是否是平衡二叉树的问题,但是实现方式稍有不同,主要是优化了递归过程中的剪枝逻辑。下面是代码的解析:

  • public boolean isBalanced(TreeNode root) 方法仍然是主接口,用于判断二叉树是否平衡,但它直接依赖于 height 方法的返回值。如果 height(root) 返回值大于等于0,则表示树是平衡的,因为只有在树不平衡的情况下 height 方法才会返回-1。

  • public int height(TreeNode root) 方法用于计算以 root 为根的子树的高度,同时在此过程中判断这棵子树是否平衡。其逻辑如下:

    • 基准情况:如果节点为空,返回高度为0,表示空树是平衡的。
    • 递归计算左子树和右子树的高度,分别赋值给 leftHeightrightHeight
    • 在这里进行了关键的平衡性检查:如果 leftHeightrightHeight 为-1,表示之前已经判断出对应的子树不平衡;或者 leftHeightrightHeight 之差的绝对值大于1,也说明当前子树不平衡。在这两种不平衡的情况下,直接返回-1,这样在上一层递归调用中就能立刻知道当前路径下的树是不平衡的,无需继续深入计算其它分支,达到剪枝效果,提高效率。
    • 如果上述条件都不满足,即当前子树是平衡的,那么返回左右子树最大高度加1作为当前子树的高度。

这种实现方式巧妙地将平衡性检查与高度计算结合在一起,通过返回-1作为不平衡的标志,能够在递归过程中尽早终止不必要的计算,是一种较为高效的解法。时间复杂度为O(n),在最好的情况下(完全平衡的树)也能保持较好的效率。

257. 二叉树的所有路径

给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
在这里插入图片描述

方法一:深度优先搜索

class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> paths = new ArrayList<String>();
        constructPaths(root, "", paths);
        return paths;
    }

    public void constructPaths(TreeNode root, String path, List<String> paths) {
        if (root != null) {
            StringBuffer pathSB = new StringBuffer(path);
            pathSB.append(Integer.toString(root.val));
            if (root.left == null && root.right == null) {  // 当前节点是叶子节点
                paths.add(pathSB.toString());  // 把路径加入到答案中
            } else {
                pathSB.append("->");  // 当前节点不是叶子节点,继续递归遍历
                constructPaths(root.left, pathSB.toString(), paths);
                constructPaths(root.right, pathSB.toString(), paths);
            }
        }
    }
}

这段代码是用来解决一个经典的二叉树问题:找出一颗二叉树中所有从根节点到叶子节点的路径,并以字符串形式返回这些路径。每条路径以节点值的序列表示,并且序列中相邻节点值之间由 “->” 连接。代码中定义了两个方法:binaryTreePathsconstructPaths

  • public List<String> binaryTreePaths(TreeNode root) 是主要的接口,接收一个 TreeNode 类型的参数 root 表示二叉树的根节点,返回值是一个字符串列表,包含所有从根到叶子的路径。首先初始化一个 List<String> 类型的 paths 用于存储所有路径,然后调用 constructPaths 函数递归构建路径,最后返回 paths

  • public void constructPaths(TreeNode root, String path, List<String> paths) 是递归辅助函数,用于构造从当前节点 root 到叶子节点的所有路径,并将这些路径添加到 paths 中。

    • 如果当前节点 root 不为空,首先将当前节点的值转换成字符串追加到路径 path 上,这里使用 StringBuffer 来避免频繁创建新的字符串对象,提高效率。
    • 接下来,检查当前节点是否为叶子节点(即没有左右子节点)。如果是叶子节点,将当前的路径加入到结果列表 paths 中。
    • 如果当前节点不是叶子节点,说明还需要继续遍历其左右子树。在递归调用前,向路径中添加一个 “->” 符号,表示路径的延续,然后分别对左子树和右子树进行递归调用,传递更新后的路径字符串。

最终,binaryTreePaths 函数会返回包含所有从根到叶子节点路径的字符串列表。这种方法有效地遍历了二叉树的所有路径,且由于使用了递归,代码较为简洁明了。

方法二:广度优先搜索

class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> paths = new ArrayList<String>();
        if (root == null) {
            return paths;
        }
        Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
        Queue<String> pathQueue = new LinkedList<String>();

        nodeQueue.offer(root);
        pathQueue.offer(Integer.toString(root.val));

        while (!nodeQueue.isEmpty()) {
            TreeNode node = nodeQueue.poll(); 
            String path = pathQueue.poll();

            if (node.left == null && node.right == null) {
                paths.add(path);
            } else {
                if (node.left != null) {
                    nodeQueue.offer(node.left);
                    pathQueue.offer(new StringBuffer(path).append("->").append(node.left.val).toString());
                }

                if (node.right != null) {
                    nodeQueue.offer(node.right);
                    pathQueue.offer(new StringBuffer(path).append("->").append(node.right.val).toString());
                }
            }
        }
        return paths;
    }
}

这段代码是另一种实现方式,用来找出一棵二叉树中所有从根节点到叶子节点的路径,并以字符串形式返回这些路径。与之前的递归解法不同,这里采用广度优先搜索(BFS)的方式遍历二叉树。代码中定义了两个队列:一个用于存储待访问的节点,另一个用于存储到达每个节点时的路径字符串。

  • public List<String> binaryTreePaths(TreeNode root) 方法是主要接口,接收一个 TreeNode 类型的参数 root 作为二叉树的根节点,返回值是一个字符串列表,包含所有从根到叶子的路径。首先初始化一个空的 List<String> paths 用于收集所有路径。如果根节点为空,直接返回空列表。然后,创建两个队列 nodeQueuepathQueue 分别用于存放节点和对应的路径字符串,将根节点及其值的字符串形式入队。

  • 使用 while 循环处理队列直到 nodeQueue 为空,每次循环:

    • 出队一个节点 node 和对应的路径字符串 path
    • 如果当前节点 node 是叶子节点(即没有左右子节点),则将当前路径加入到结果列表 paths 中。
    • 如果当前节点有子节点,依次将左子节点和右子节点(如果存在)入队,并构造它们的新路径字符串(基于当前路径加上 “->” 和节点值),然后也将新路径入队 pathQueue
  • 循环结束后,paths 列表中包含了所有从根到叶子的路径,直接返回即可。

这种方法利用了广度优先搜索的特性,逐层遍历树的节点,使用队列维护待处理的节点和路径,能够有效地遍历整棵树并收集所有路径,同时避免了递归可能导致的栈溢出问题。

404. 左叶子之和

给定二叉树的根节点 root ,返回所有左叶子之和。
在这里插入图片描述

方法一:深度优先搜索

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        return root != null ? dfs(root) : 0;
    }

    public int dfs(TreeNode node) {
        int ans = 0;
        if (node.left != null) {
            ans += isLeafNode(node.left) ? node.left.val : dfs(node.left);
        }
        if (node.right != null && !isLeafNode(node.right)) {
            ans += dfs(node.right);
        }
        return ans;
    }

    public boolean isLeafNode(TreeNode node) {
        return node.left == null && node.right == null;
    }
}

这段代码是用来求解一个二叉树问题的,具体是计算给定二叉树中所有左叶子节点之和。代码定义了三个方法:sumOfLeftLeavesdfsisLeafNode

  • public int sumOfLeftLeaves(TreeNode root) 是主方法,接收一个 TreeNode 类型的参数 root 作为二叉树的根节点,返回值是所有左叶子节点的值之和。如果根节点为空,直接返回0。否则,调用深度优先搜索(DFS)方法 dfs 并传入根节点,返回其结果。

  • public int dfs(TreeNode node) 是深度优先搜索的实现,用于递归地遍历二叉树。对于当前节点 node

    • 首先初始化答案变量 ans 为0。
    • 如果当前节点的左子节点不为空,判断这个左子节点是否为叶子节点(调用 isLeafNode 方法)。如果是,直接将该左叶子节点的值累加到 ans;如果不是叶子节点,则递归调用 dfs 并累加返回值。
    • 接着,如果当前节点的右子节点不为空且不是叶子节点,递归调用 dfs 并累加右子树的返回值。注意这里只对非叶子的右子节点进行递归,因为题目要求的是左叶子节点之和,右子节点仅在它不是叶子节点时才可能贡献额外的和(通过其自身的左叶子节点)。
    • 最后返回 ans,即经过当前节点后累加的左叶子节点之和。
  • public boolean isLeafNode(TreeNode node) 是一个辅助方法,用于判断给定的节点是否为叶子节点(即没有左右子节点),返回布尔值。

通过这样的递归遍历,代码能高效地计算出二叉树中所有左叶子节点的值之和。

方法二:广度优先搜索

class Solution {
    public int sumOfLeftLeaves(TreeNode root) {
        if (root == null) {
            return 0;
        }

        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        queue.offer(root);
        int ans = 0;
        while (!queue.isEmpty()) {
            TreeNode node = queue.poll();
            if (node.left != null) {
                if (isLeafNode(node.left)) {
                    ans += node.left.val;
                } else {
                    queue.offer(node.left);
                }
            }
            if (node.right != null) {
                if (!isLeafNode(node.right)) {
                    queue.offer(node.right);
                }
            }
        }
        return ans;
    }

    public boolean isLeafNode(TreeNode node) {
        return node.left == null && node.right == null;
    }
}

这段代码提供了另一种解决方案,使用广度优先搜索(BFS)的方法来计算给定二叉树中所有左叶子节点的值之和。与之前的深度优先搜索(DFS)版本相比,这里使用了队列来进行层次遍历。代码中定义了两个方法:sumOfLeftLeavesisLeafNode

  • public int sumOfLeftLeaves(TreeNode root) 是主方法,接收一个 TreeNode 类型的参数 root 作为二叉树的根节点,返回值是所有左叶子节点的值之和。如果根节点为空,直接返回0。初始化一个队列 queue,并将根节点放入队列。定义一个变量 ans 用于累计左叶子节点的值。然后进入一个循环处理队列直到其为空。

    • 在循环中,每次从队列中取出一个节点 node
    • 检查 node 的左子节点是否存在,如果存在并且是叶子节点(调用 isLeafNode 判断),则将左叶子节点的值累加到 ans;如果左子节点不是叶子节点,则将它加入队列以便后续遍历。
    • 接着检查 node 的右子节点,如果右子节点存在且不是叶子节点,则将其加入队列。这里右子节点的叶子状态不影响累加和,但可能包含其他左叶子节点,故需继续遍历。
  • 循环结束后,返回累计的左叶子节点值之和 ans

  • public boolean isLeafNode(TreeNode node) 是一个辅助方法,用于判断给定的节点是否为叶子节点,即没有左右子节点,返回布尔值。

这种方法通过广度优先搜索遍历整棵树,每一步只访问到每一层的节点,空间复杂度相对较低,适用于树的宽度不是非常大的情况。它直接访问每个节点并立即判断是否为左叶子节点,逻辑直观且易于理解。

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

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

相关文章

四天学会JS高阶(学好vue的关键)——构造函数数据常用函数(理论+实战)(第二天)

一、对象创建引发构造函数产生 1.1 创建对象三种方式&#xff1a; 利用对象字面量创建对象 const obj {name: 佩奇}注&#xff1a;对象字面量的由来&#xff1a;即它是直接由字面形式&#xff08;由源代码直接&#xff09;创建出来的对象&#xff0c;而不是通过构造函数或者…

开箱测评!吸猫毛除味神器,希喂FreAir Lite宠物空气净化器实测

掉毛季又来了&#xff0c;猫咪的毛发满天飞&#xff0c;怎么办&#xff1f;我家掉毛怪一到季节就开始掉老多毛&#xff0c;关键还喜欢在家里打架跑酷&#xff01;天上地下都是毛&#xff01;为了减少家里空气中浮毛&#xff0c;你做过那些努力呢&#xff1f;最近猫掉毛掉的&…

设置height:100%不生效的原因

之前网课案例总是不屑于去看&#xff0c;因为总觉得太花时间&#xff0c;但是不可否认的是&#xff0c;认真去看还是会有收获的&#xff0c;而且常有意外收获 昨天在看实现动画效果的综合案例中&#xff0c;意外解决了我长久以来的一个疑问&#xff1a;为什么给元素设置height…

论文精读--InstructGPT

模型效果取决于数据效果&#xff0c;但在精细度上控制不够&#xff0c;只是大力出奇迹&#xff0c;这样有很大的问题&#xff1a; &#xff08;1&#xff09;数据量太多或者没有这方面的数据&#xff0c;模型学不会怎么办 &#xff08;2&#xff09;安全性问题&#xff0c;模…

踩坑——纪实

开发踩坑纪实 1 npm安装1.1 查看当前的npm镜像设置1.2 清空缓存1.3 修改镜像1.4 查看修改结果1.5 重新安装vue 2 VScode——NPM脚本窗口找不到3 springboot项目中updateById()失效4 前端跨域4.1 后端加个配置类4.2 CrossOrigin注解 5 路由出口6 springdoc openapi3 swagger3文件…

VMware 虚拟机 VM10~17系列安装教程(功能最强大的电脑虚拟机软件)

前言 VMware是功能最强大的虚拟机软件&#xff0c;用户可以在虚拟机同时运行各种操作系统&#xff0c;进行开发、测试、演示和部署软件&#xff0c;虚拟机中复制服务器、台式机和平板环境&#xff0c;每个虚拟机可分配多个处理器核心、主内存和显存。 系统要求 VM17 VM16&am…

《ESP8266通信指南》番外-(附完整代码)ESP8266获取DHT11接入(基于Lua)

前言 此篇为番外篇,是 ESP8266 入门的其他功能教程,包括但不限于 DHT11 驱动TCP 通信Thingsboard 平台的接入阿里云物联网云平台接入华为云平台接入 1. 小节目标 使用 Lua 驱动 DHT11 传感器,获取温湿度的值 2. 进入主题 NodeMCU 基于 LUA 相关资料 官方文档&#xff1a;…

【每日刷题】Day47

【每日刷题】Day47 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 112. 路径总和 - 力扣&#xff08;LeetCode&#xff09; 2. 2404. 出现最频繁的偶数元素 - 力扣&am…

Visual Basic6.0零基础教学(5)—VB的输入输出,顺序和选择结构

VB的输入输出和控制结构 文章目录 VB的输入输出和控制结构前言一、输入输出1. InputBox 输入2.MsgBox输出print 输出 二、控制结构1.顺序结构赋值语句 2.选择结构if ... then单分支if ... then...else.... 双分支if ... then... elseif ... then .. else ... 多分支Select Case…

视频监控管理平台LntonCVS监控视频汇聚融合云平台主要功能应用场景介绍

随着网络技术的不断发展和万物互联时代的到来&#xff0c;视频融合在一些系统集成项目及综合管理应用中变得日益重要。本文以LntonCVS视频融合云平台为案例&#xff0c;探讨视频融合的对象及其应用场景。 1. 视频监控设备 视频监控摄像设备是各种视频应用项目的基础部分。在视…

CSS单行、同行文本左右对齐

再项目需求中&#xff0c;UI小姐姐常常要考虑项目的排版样式更简洁高级&#xff0c;常常会在项目设置内容或者字体两端对齐的效果&#xff0c;比如&#xff0c;在做表单时我们经常遇到让上下两个字段对齐的情况&#xff0c;比如姓名&#xff0c; 手机号码&#xff0c; 出生地等…

VUE3+Vite+vant4从零开始构建前端项目

VUE3Vitevant4从零开始构建前端项目 1. 环境准备Node.js 安装 2. Vite 构建项目3. 集成Vant41. 安装Vant 组件2. 引入组件3. 使用vant按钮组件 1. 环境准备 Node.js 安装 Node.js官网地址&#xff1a;https://nodejs.p2hp.com/ 下载最新的版本&#xff0c;下载文件为msi结尾的…

[力扣]——70.爬楼梯

题目描述&#xff1a; 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 本题较为简单&#xff0c;主要用到递归思想 int fun(int n,int memo[]) {if(memo[n]!-1) //如果备忘录中已经有记录了…

区块链的运行原理与演示

目录 前言 具体演示 1、在浏览器中输入区块链演示网址&#xff1a; 2、创建新区块 3、篡改区块信息使其无效 4、新增P2P 网络节点。 5、节点连接。 6、区块信息同步 总结 前言 区块链系统是由一系列分布在全球各地的分布式节点组成的。这些节点互不隶属&#xff0c;通过…

Sonatype Nexus Repository 3 路径遍历漏洞复现(CVE-2024-4956)

0x01 产品简介 Sonatype Nexus Repository 是美国Sonatype公司的一款存储库管理器,用于存储和分发软件组件、构建工件和 Docker 容器。它支持多种包格式,与 CI/CD 工具集成,并提供安全性和合规性功能。 0x02 漏洞概述 Sonatype Nexus Repository 3 存在路径遍历漏洞(CVE-…

数据结构(二)单链表

一、链表 &#xff08;一&#xff09;概念 逻辑结构&#xff1a;线性 存储结构&#xff1a;链式存储&#xff0c;在内存中不连续 分为有头链表和无头链表 同时又细分为单向、循环、双向链表 &#xff08;二&#xff09;有头单向链表示意图 以下数据及地址只是为了方便理解…

【Linux】文件系统和软硬链接

目录 一、认识文件系统 二、认识磁盘 三、磁盘文件系统 3.1 磁盘存储的抽象逻辑结构 3.2 磁盘文件系统图 3.3 创建和删除文件 3.4 如何理解目录&#xff1f; 3.5 如何查找一个文件 3.6 查找文件的一般流程 3.7 如何确定文件所在的分区 3.8 总结 四、软硬链接 4.1 …

30、QUiLoader 在程序运行时读取UI 文件中的信息

QUiLoader 类可让独立应用程序在运行时使用UI 文件中存储的信息&#xff0c;进而可以分离UI设计工作。 一、使用Qt 设计师-Qt Designer创建ui文件 打开Qt Designer&#xff0c;选择“创建” 往中央区域拖住几个控件&#xff0c;进行布局&#xff0c;更改三个控件的objectName…

参考文献交叉引用两个文献,逗号隔开

1.引用两个参考文献&#xff0c;定位到word正文中需要引用的位置&#xff0c;然后插入-交叉引用&#xff0c;引好文献 2.选中两个参考文献&#xff0c;切换域代码&#xff0c;然后进行修改&#xff1a; 改为 上面的两张图片中的点是空格的含义&#xff0c;word中按ctrlshift8就…

Qt | QGridLayout 类(网格布局)

01、上节回顾 Qt | QBoxLayout 及其子类(盒式布局)02、QGridLayout 简介 1、网格布局原理(见下图): 基本原理是把窗口划分为若干个单元格,每个子部件被放置于一个或多个单元格之中,各 单元格的大小可由拉伸因子和一行或列中单元格的数量来确定,若子部件的大小(由 sizeH…