代码随想录-Day17

news2024/11/20 11:19:51

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) 是一个辅助方法,用于判断给定的节点是否为叶子节点,即没有左右子节点,返回布尔值。

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

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

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

相关文章

WPF水流动画(使用转换器模拟逻辑门控制水流信号)

前言 在使用WPF绘制流程图并模拟水流动画时&#xff0c;往往既需要控制阀泵的开合&#xff0c;又要控制动画启停。倘若能够将阀泵的开合与动画播放建立逻辑关系&#xff0c;这样就能够让业务代码“专心”地去控制阀泵开关&#xff0c;而不需要处理界面的展示。 动画示例 说明…

2024-5-4-从0到1手写配置中心Config之基于h2的config-server

添加依赖 新建的web工程中添加h2的依赖 添加h2的配置 设置数据源和密码设置初始化sql语句打开h2的控制台 初始化语句创建一个config表&#xff0c;保存服务配置信息。 完成CRUD接口 controller类 mapper接口 测试 在web控制台可以看到sql已经初始化完成&#xff0c;crud接口…

Postman进阶功能-Mock服务与监控

大家好&#xff0c;前面跟大家分享一些关于 Postman 的进阶功能&#xff0c;当我们深入探索 Postman 的进阶功能时&#xff0c;Mock 服务与监控这两个重要方面便跃然眼前。 首先&#xff0c;Mock 服务为我们提供了一种灵活便捷的方式&#xff0c;让我们在某些实际接口尚未准备好…

Transformer系列专题(二)——multi-headed多头注意力机制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、什么是multi-headed&#xff08;多头注意力机制&#xff09;二、multi-headed三、multi-headed结果四、堆叠多层总结 前言 在实践中&#xff0c;当给定相同…

四川古力科技抖音小店,创新科技点亮购物新体验

在这个数字化浪潮汹涌的时代&#xff0c;四川古力科技以其前瞻性的战略眼光和创新能力&#xff0c;闪耀于抖音小店这片电商新蓝海&#xff0c;开启了未来购物的新纪元。作为一家集技术研发、产品创新、市场营销于一体的科技型企业&#xff0c;古力科技不仅为消费者带来了前所未…

Android Studio 与 Gradle 及插件版本兼容性

Android Studio 开始新项目时&#xff0c;会自动创建其中部分文件&#xff0c;并为其填充合理的默认值。 项目文件结构布局&#xff1a; 一、Android Gradle 及插件作用&#xff1a; Android Studio 构建系统以 Gradle 为基础&#xff0c;并且 Android Gradle 插件 (AGP) 添加…

游戏行业 2024 Q1报告 | 国内同比上升7.6%,海外收入同比环比双增长,码住!

作为中国音像与数字出版协会主管的中国游戏产业研究院的战略合作伙伴&#xff0c;伽马数据发布了《2024年1—3月中国游戏产业季度报告》。 数据显示&#xff0c; 2024年1—3月&#xff0c;中国游戏市场实际销售收入726.38亿元&#xff0c;同比增长7.60%&#xff0c;主要受移动游…

WXML模板语法-数据绑定

1.数据绑定的基本原则 (1)在data中定义数据 (2)在WXML中使用数据 2.在data页面中定义数据&#xff1a;在页面对应的.js文件中&#xff0c;把数据定义在data对象中即可 &#xff08;这里打错了 应该是数组类型的数据... 报意思啊&#xff09; 3.Mustache语法的格式 把data中的…

Element Plus/vue3 无限级导航实现

在使用element plus 时&#xff0c;最初要使用的就是导航组件了&#xff0c;官网上看到的也就是写死的一级/二级导航&#xff0c;那么如何设计一个无限级且动态的导航呢&#xff1f;毋庸置疑&#xff0c;递归。废话不多说&#xff0c;直接看代码和效果&#xff1a; 代码&#x…

单链表oj

练习 1. 删除val节点 oj链接 这道题最先想出来的方法肯定是在遍历链表的同时删除等于val的节点&#xff0c;我们用第二中思路:不等于val的节点尾插&#xff0c;让后返回新节点。代码如下&#xff1a; struct ListNode* removeElements(struct ListNode* head, int val) {str…

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

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

MyBatis入门——MyBatis XML配置文件(3)

目录 一、配置连接字符串和MyBatis 二、写持久层代码 1、添加 mapper 接口 2、添加 USerInfoXmlMapper.xml 3、测试类代码 三、增删改查操作 1、增&#xff08;Insert&#xff09; 返回自增 id 2、删&#xff08;Delete&#xff09; 3、改&#xff08;update&#xf…

【Linux】-Tomcat安装部署[12]

目录 简介 安装 安装部署JDK环境 解压并安装Tomcat 简介 Tomcat是由Apache开发的一个Servlet容器&#xff0c;实现了对Servlet和JSP的支持&#xff0c;并提供了作为Web服务器的一些特有功能&#xff0c;如Tomcat管理和控制平台、安全域管理和Tomcat阀等。 简单来说&#…

嵌入式学习——3——IO分类模型

1、阻塞IO和非阻塞IO 1.1 阻塞IO - 在阻塞IO模型中&#xff0c;当一个IO操作&#xff08;如读取或写入&#xff09;开始时&#xff0c;如果数据没有准备好&#xff0c;程序会被挂起&#xff08;即阻塞&#xff09;&#xff0c;直到数据准备好并且IO操作完成。 - 在数据准备阶段…

sql server【 特定分隔符隔开的字符串转表】和【 列转逗号隔开的字符串】

文章目录 引言I 特定分隔符隔开的字符串转表II Sql Server 列转逗号隔开的字符串2.1 多列转行,逗号分隔(字段拼接/字段分割)2.1 案例引言 Sql Server 列转逗号隔开的字符串 和 逆转,常用于数据导出和数据查询。 I 特定分隔符隔开的字符串转表 CREATE FUNCTION [dbo].[GetIDLi…

LitCTF

[LitCTF 2023]enbase64 base 64 里面有一个换表的函数 写代码 #include<stdio.h> #include<string.h> #include<stdlib.h> int main() {char *result; char Destination[65]; int v3[65];int j;int i; char Source[]"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde…

【配置】雷池WAF社区版安装

官方文档点击跳转 什么是雷池 雷池&#xff08;SafeLine&#xff09;是长亭科技耗时近 10 年倾情打造的 WAF&#xff0c;核心检测能力由智能语义分析算法驱动。 什么是 WAF WAF 是 Web Application Firewall 的缩写&#xff0c;也被称为 Web 应用防火墙。 区别于传统防火墙…

MySql--SQL语言

目录 SQl---DDL 结构定义 创建、删除 数据库 代码 运行 设计表 数据类型 整数 浮点数 主键 约束 主键自增长 默认值 字段注释 创建、删除 表 代码 运行 代码 代码 运行 SQL---DML 数据操纵 插入数据 代码 运行 代码 运行 代码 运行 代码 …

sqlserver查看索引碎片,并整理

DBCC SHOWCONTIG WITH ALL_INDEXES --查看所有表的索引碎片情况 DBCC SHOWCONTIG(fq_viewvform) --指定表索引碎片情况 dbcc dbreindex(fq_viewvform) --重建表索引 DBCC SHOWCONTIG(fq_viewvform) --检查重建后表索引碎片情况 查看全库索引碎片情况&#xff1a; 查看单表索引…

H800基础能力测试

H800基础能力测试 参考链接A100、A800、H100、H800差异H100详细规格H100 TensorCore FP16 理论算力计算公式锁频安装依赖pytorch FP16算力测试cublas FP16算力测试运行cuda-samples 本文记录了H800基础测试步骤及测试结果 参考链接 NVIDIA H100 Tensor Core GPU Architecture…