算法打卡day15

今日任务:

1)110.平衡二叉树

2)257. 二叉树的所有路径

3)404.左叶子之和

110.平衡二叉树

题目链接:110. 平衡二叉树 - 力扣(LeetCode)

给定一个二叉树,判断它是否是高度平衡的二叉树。
本题中,一棵高度平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1

示例 1:
给定二叉树 [3,9,20,null,null,15,7]
输出:true

示例 2:
给定二叉树 [1,2,2,3,3,null,null,4,4]
输出:False

文章讲解:代码随想录 (programmercarl.com)

视频讲解:后序遍历求高度,高度判断是否平衡 | LeetCode:110.平衡二叉树哔哩哔哩bilibili

思路:

node的高度:node节点到最底层叶子节点的高度

这题弄清楚这个就比较好做了,采用递归法后序遍历(左右中)

1.确定递归函数的参数和返回值:将节点传入递归函数中,返回这个节点的高度

2.终止条件:递归的过程中依然是遇到空节点了为终止,返回0,表示当前节点为根节点的树高度为0

3.单层递归逻辑:判断传入节点左右两个子树的高度差是否超过1

如果不超过1,说明是平衡的,则继续检查其左右子树是否也是平衡的。如果超过1,则不平衡,直接返回false。因为返回值为高度,这里为了返回值类型统一,我们可以将不平衡设为-1,如果返回值为-1,则表示不平衡;否则平衡,返回该节点高度

class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution:def isBalanced(self, root: [TreeNode]) -> bool:if self.getHeight(root) != -1:return Trueelse:return Falsedef getHeight(self, node):if not node:return 0leftHeight = self.getHeight(node.left)  # 左rightHight = self.getHeight(node.right)  # 右if leftHeight == -1 or rightHight == -1:return -1  # 这里直接终止返回-1,不要在用height记录了,因为左右高度均为-1时,在后面判断中,两个相减是等于0的,会使height重新赋值为0else:height = max(leftHeight, rightHight) + 1  # 求出该节点高度# 如果左右子树高度差大于1,则用-1标记if abs(leftHeight - rightHight) > 1:height = -1# 如果之前没有返回-1,则表明该节点之前的子树都符合要求return height

感想:

避免重复计算: 为了避免重复计算,这题我们采用下而上的方式计算节点,也就是后序遍历,这样可以确保每个节点的高度只计算一次

适时剪枝: 在检查节点平衡性时,如果发现某个节点所在的子树已经不平衡,可以及早终止递归,提前返回结果,避免不必要的计算。

257. 二叉树的所有路径

题目链接:257. 二叉树的所有路径 - 力扣(LeetCode)

给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。

示例:
输入:[1,2,3,None,5,None,None]
输出:["1->2->5","1->3"]

文章讲解:代码随想录 (programmercarl.com)

视频讲解:递归中带着回溯,你感受到了没?| LeetCode:257. 二叉树的所有路径哔哩哔哩bilibili

思路:

当我们想要找到二叉树中所有从根节点到叶子节点的路径时,可以使用深度优先搜索(DFS)算法(前序遍历-->中左右)。我们可以从根节点开始,沿着每条路径向下遍历二叉树,直到到达叶子节点。在遍历过程中,我们将经过的节点值记录下来,直到到达叶子节点,然后将路径添加到结果中。

下面是具体的实现逻辑:

1.创建一个空列表 result 用于存储所有的路径。

2.编写一个递归函数 traversal,它接收当前节点 node 和当前路径 path 作为参数。

3.在递归函数中,首先将当前节点的值加入到路径 path 中。

4.判断当前节点是否为叶子节点(即没有左右子节点)。如果是叶子节点,则将当前路径 path 加入到结果列表 result 中。

5.如果当前节点不是叶子节点,则递归调用 traversal 函数分别遍历其左右子节点。在递归调用时,需要将当前路径 path 作为参数传递给下一级。

6.最后,在主函数中调用 traversal 函数,从根节点开始遍历二叉树,并将结果返回。

思路比较简单,但要注意里面的回溯过程

# Definition for a binary tree node.
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution:def binaryTreePaths(self, root: [TreeNode]) -> list[str]:path = []result = []if not root:return resultself.traversal(root, path, result)return resultdef traversal(self, node: [TreeNode], path: list[str], result: list[str]) -> None:# 将当前节点值加入路径中path.append(str(node.val))  # 中# 遇到叶子节点终止if not node.left and not node.right:sPath = '->'.join(path)result.append(sPath)return# 如果不是叶子节点,继续递归遍历左右子树if node.left:  # 左self.traversal(node.left, path, result)path.pop()  # 回溯if node.right:  # 右self.traversal(node.right, path, result)path.pop()  # 回溯

这一种是比较完整的写法,后面采用了隐藏回溯的方法。隐藏回溯方法核心是为了保证path的独立性,我们需要构建新的字符串传入,而不是path本身

第一种采用列表切片实现,相当于传入的path副本

# Definition for a binary tree node.
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution2:def binaryTreePaths(self, root: [TreeNode]) -> list[str]:path = []result = []if not root:return resultself.traversal(root, path, result)return resultdef traversal(self, node: [TreeNode], path:list[int], result: list[str]) -> None:path.append(node.val)if not node.left and not node.right:result.append('->'.join(map(str, path)))if node.left:self.traversal(node.left, path[:], result)if node.right:self.traversal(node.right, path[:], result)

在 Python 中,列表是可变对象,如果直接传递列表 path,则在递归调用过程中可能会修改当前路径列表,这会导致不正确的结果。因为在递归过程中,我们会多次修改 path,而不是每次递归调用都使用相同的初始路径。

所以,为了避免这种情况,我们需要在每次递归调用时传递当前路径的副本,而不是直接传递当前路径本身。通过使用切片 path[:],我们创建了当前路径的一个副本,并将副本传递给递归调用的下一级。这样,即使在递归调用中修改了副本 path,原始的当前路径列表 path 也不会受到影响。

简而言之,传递 path[:] 会创建当前路径的一个副本,这样可以确保每次递归调用使用的路径都是独立的,避免了在递归调用过程中修改原始路径的情况。

第二种采用字符串拼接实现

# Definition for a binary tree node.
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = right# 隐藏回溯版本(采用字符串拼接)
class Solution3:def binaryTreePaths(self, root: [TreeNode]) -> list[str]:path = ''result = []if not root: return resultself.traversal(root, path, result)return resultdef traversal(self, cur: TreeNode, path: str, result: list[str]) -> None:path += str(cur.val)# 若当前节点为leave,直接输出if not cur.left and not cur.right:result.append(path)if cur.left:# + '->' 是隐藏回溯self.traversal(cur.left, path + '->', result)if cur.right:self.traversal(cur.right, path + '->', result)

在递归调用 traversal 方法时,我们传递的是 path + '->',而不是 path 本身。这里的 path + '->' 是一个新的字符串,它在每一次递归调用中都是独立的,不会修改原始的 path 字符串。

看整个代码,我们传入左右树的path依旧是当前递归中的path,并没有左节点递归的影响。通过这种方式,我们避免了在递归调用过程中修改原始的 path 字符串,从而确保了每次递归调用使用的路径都是独立的。

404.左叶子之和

题目链接:404. 左叶子之和 - 力扣(LeetCode)

给定一个二叉树,返回所有从根节点到叶子节点的路径。
说明: 叶子节点是指没有子节点的节点。

示例:
输入:[1,2,3,None,5,None,None]
输出:["1->2->5","1->3"]

文章讲解:代码随想录 (programmercarl.com)

视频讲解:二叉树的题目中,总有一些规则让你找不到北 | LeetCode:404.左叶子之和哔哩哔哩bilibili

思路:

这题我们采用DFS中前序遍历(中左右)

递归遍历并计算左叶子节点的累加和:

我们需要一个递归函数来遍历二叉树并计算左叶子节点的累加和。这个递归函数将会是我们解决问题的核心。
在遍历的过程中,我们需要记录当前节点的值,并判断其是否为左叶子节点。
如果是左叶子节点,则将其值累加到一个变量中。
然后递归遍历左右子树,分别将左右子树的左叶子节点的值累加到上面的变量中。
返回累加和:

最后,我们返回累加和作为结果。

class Solution:def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:# 入口函数,调用递归函数return self.traversal(root)def traversal(self, node: Optional[TreeNode]) -> int:# 递归函数,计算左叶子节点的累加和if not node:return 0left_sum = 0  # 初始化左叶子节点的累加和为0if node.left and not node.left.left and not node.left.right:# 如果左子节点存在且为叶子节点,则累加其值到 left_sum 中left_sum += node.left.val# 递归遍历左右子树,将左右子树的左叶子节点值累加到 left_sum 中left_sum += self.traversal(node.left)left_sum += self.traversal(node.right)return left_sum  # 返回左叶子节点的累加和

感想:

这一题核心有几个要注意的地方

1.在递归函数中,确保对左右子树的遍历不会重复访问节点。

2.正确处理空节点的情况,避免出现空指针异常。

3.确保在每一级递归调用中,局部变量的值不会互相影响。

4.理解递归的返回值含义,确保递归函数的返回值是符合预期的。

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

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

相关文章

基于大数据的空气质量预测和可视化分析

城市空气质量数据采集系统设计与实现 🏙️ 研究背景 🌬️ 城市化与环境挑战:随着城市化进程的加快,环境污染问题,尤其是空气质量问题,已成为公众关注的焦点。数据监测的重要性:城市空气质量数…

控价其实是对品牌市场的保护

品牌发展过程中,如果有越来越多的经销商加入,必然要做好控价,否则渠道的混乱,会使得品牌价值受损,比如低价的出现,会影响正规经销商的出货,使其竞争力增加,同时价格的不稳定会连带产…

小游戏-扫雷

扫雷大多人都不陌生,是一个益智类的小游戏,那么我们能否用c语言来编写呢, 我们先来分析一下扫雷的运行逻辑, 首先,用户在进来时需要我们给与一个菜单,以供用户选择, 然后我们来完善一下&#…

Vue 实现带拖动功能的时间轴

1.效果图 2. 当使用timeline-slider-vue组件时,你可以设置以下属性: date:用于设置时间轴滑块的初始日期,格式通常为 YYYY-MM-DD。 mask:一个布尔值,用于控制是否显示背景遮罩。 markDate:一…

Java 面试宝典:什么是大 key 问题?如何解决?

大家好,我是大明哥,一个专注「死磕 Java」系列创作的硬核程序员。 本文已收录到我的技术网站:https://skjava.com。有全网最优质的系列文章、Java 全栈技术文档以及大厂完整面经 回答 Redis 大 key 问题是指某个 key 对应的 value 值很大&am…

C语言——sizeof与strlen的对比

一.sizeof 我们在学习操作符的时候&#xff0c;就了解到了sizeof操作符&#xff0c;它的作用是求参数所占内存空间的大小&#xff0c;单位是字节。如果参数是一个类型&#xff0c;那就返回参数所占的字节数。 #include <stdio.h>int main() {int a 10;size_t b sizeo…

Mamba 基础讲解【SSM,LSSL,S4,S5,Mamba】

文章目录 Mamba的提出动机TransformerRNN Mama的提出背景状态空间模型 (The State Space Model, SSM)线性状态空间层 (Linear State-Space Layer, LSSL)结构化序列空间模型 &#xff08;Structured State Spaces for Sequences, S4&#xff09; Mamba的介绍Mamba的特性一&#…

美团2024届秋招笔试第二场编程真题

要么是以0开头 要么以1开头 选择最小的答案累加 import java.util.Scanner; import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和…

C# 右键快捷菜单(上下文菜单)的两种实现方式

在C#中&#xff0c;ContextMenuStrip是一种用于创建右键菜单的控件。它提供了一种方便的方式来为特定的控件或窗体添加自定义的上下文菜单选项。有两种实现方式&#xff0c;如下&#xff1a; 一.通过ContextMenuStrip控件实现 1.从工具箱中拖一个ContextMenuStrip控件到窗体上…

LLM - 大语言模型的分布式训练 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136924304 大语言模型的分布式训练是一个复杂的过程&#xff0c;涉及到将大规模的计算任务分散到多个计算节点上。这样做的目的是为了处…

领域、系统和组织-《实现领域驱动设计》中译本评点-第2章(4)

相关链接 DDD领域驱动设计批评文集>> 汪峰哭晕在厕所-《实现领域驱动设计》中译本评点-第2章&#xff08;1&#xff09; 可不是乱打的-《实现领域驱动设计》中译本评点-第2章&#xff08;2&#xff09; “领域”的错误定义-《实现领域驱动设计》中译本评点-第2章&…

Tomcat介绍,Tomcat服务部署

目录 一、Tomcat 介绍 二、Tomcat 核心技术和组件 2.1、Web 容器&#xff1a;完成 Web 服务器的功能 2.2、Servlet 容器&#xff0c;名字为 catalina&#xff0c;用于处理 Servlet 代码 2.3、JSP 容器&#xff1a;用于将 JSP 动态网页翻译成 Servlet 代码 Tomcat 功能组件…

Window全网解析网站下载视频

全网解析网站下载视频 介绍m3u8格式cbox格式 解析视频下载的方法方法一解析视频下载视频 方法二老王浏览器下载使用浏览器解析下载视频 总结 介绍 今天分享一下如何解析网页中的视频进行下载。通常情况下我们打开的某某网站的视频是不提供下载接口的&#xff0c;甚至说你下载了…

ClickHouse--11--物化视图

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.物化视图什么是物化视图? 1.1 普通视图1.2 物化视图1.3 优缺点1.4 基本语法1.5 在生产环境中创建物化视图1.6 AggregatingMergeTree 表引擎3.1 概念3.2 Aggregat…

面试算法-87-分隔链表

题目 给你一个链表的头节点 head 和一个特定值 x &#xff0c;请你对链表进行分隔&#xff0c;使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。 你应当 保留 两个分区中每个节点的初始相对位置。 示例 1&#xff1a; 输入&#xff1a;head [1,4,3,2,5,2], x …

【JAVA】通过JAVA实现用户界面的登录

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法|MySQL| ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-wyCvaz0EBNwHcwsi {font-family:"trebuchet ms",verdana,arial,sans-serif;f…

Linux系统——硬件命令

目录 一.网卡带宽 1.查看网卡速率——ethtool 网卡名 2.查看mac地址——ethtool -P 网卡名 二、内存相关 1.显示系统中内存使用情况——free -h 2.显示内存模块的详细信息——dmidecode -t memory 三、CPU相关 1.查看CPU架构信息——lscpu 2.性能模式 四、其他硬件命…

C语言字节对齐关键字#pragma pack(n)的使用

0 前言 在进行嵌入式开发的过程中&#xff0c;我们经常会见到对齐操作。这些对齐操作有些是为了便于实现指针操作&#xff0c;有些是为了加速对内存的访问。因此&#xff0c;学习如何使用对齐关键字是对于嵌入式开发是很有必要的。 1 对齐规则 1.0 什么叫做对齐 众所周知&a…

牛客NC170 最长不含重复字符的子字符串【高频 中等 map、滑动窗口 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/48d2ff79b8564c40a50fa79f9d5fa9c7 思路 用一个hashmap记录每个字母的index如果这个字母已经在map里了说明已经有重复了这样就更新看这个字母上次出现的index需要注意的是这种情况&#xff1a;“bacbca”这里的a…

PCB中常用电子器件封装学习——【一网打尽】

‘ 上图是这个世界上大概所有的封装种类&#xff0c;当然我们日常硬件电路设计肯定用不到这么多&#xff0c;接下来我将介绍几种工程上常用的封装&#xff0c;配以图片方便大家理解学习。在电子器件选型的时候&#xff0c;避免选择到一些非常难以焊接的封装电子器件。