【二叉树】【2.1遍历二叉树】【刷题笔记】【灵神题单】

关注二叉树的三个问题:

  1. 什么情况适合自顶向下?什么时候适合用自底向上
  2. 一般来说,DFS的递归边界是空节点,什么情况下要额外把叶子节点作为递归边界?
  3. 在什么情况下,DFS需要有返回值?什么情况不需要有返回值?

三种遍历顺序

本质就是根节点位置决定前中后序遍历

  1. 前序遍历
    • 顺序根节点 - 左子树 - 右子树。
    • 特点:先处理根节点,然后依次深入左子树和右子树进行相同规则的遍历。可以快速获取根节点相关信息,适用于复制二叉树等操作。
  2. 中序遍历
    • 顺序:左子树 - 根节点 - 右子树。
    • 特点:对于二叉搜索树,能得到有序的节点序列。先深入左子树,再访问当前层根节点,最后遍历右子树,常用于二叉搜索树的排序相关操作。
  3. 后序遍历
    • 顺序:左子树 - 右子树 - 根节点
    • 特点:最后处理根节点,在删除二叉树节点或者需要先获取左右子树信息(如计算二叉树高度)的场景比较适用,先递归处理左右子树,最后处理根节点。

144.二叉树的前序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:res = []def dfs(node):if node is None: returnres.append(node.val)    # 根节点值 dfs(node.left)		    # 左节点dfs(node.right)			# 右节点dfs(root)return res

94.二叉树的中序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:res = []def dfs(node):if node is None: returndfs(node.left)res.append(node.val)dfs(node.right)dfs(root)return res

145.二叉树的后序遍历

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:res = []def dfs(node):if not node: return dfs(node.left)dfs(node.right)res.append(node.val)dfs(root)return res

872.叶子相似的树

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:# dfs 递归到叶子节点时(当前节点无左右子节点),将当前节点值放入res=[]# 用啥顺序遍历?def dfs(node):ans = []# 当前空节点,直接returnif not node:return# 递归到了叶子节点if node.left is node.right:ans.append(node.val)# 前序遍历?dfs(node.left)dfs(node.right)return ansreturn dfs(root1) == dfs(root2)
——————————————————————
解答错误
21 / 47 个通过的测试用例官方题解
输入
root1 =
[1,2,3]
root2 =
[1,3,2]添加到测试用例
输出
true
预期结果
false

以为是递归顺序的原因,换成了中序遍历,结果并没有改变。

这段代码的核心错误在于每次每次调用dfs函数,都重新初始化了一个空列表[ ],这样就无法正确地在整棵树地遍历过程中收集到所有叶子节点的值到一个统一的列表!

正确做法是,在函数外部初始化结果列表ans1和ans2,然后将这个列表不断递归更新,每次都传入下一层递归函数!
class Solution:def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool:# dfs 递归到叶子节点时(当前节点无左右子节点),将当前节点值放入res=[]# 用啥顺序遍历?ans1 =[]ans2 = []def dfs(node, ans):# 当前空节点,直接returnif not node:return           # 递归到了叶子节点if node.left is None and node.right is None:ans.append(node.val)                                       # 前序遍历?dfs(node.left, ans)dfs(node.right, ans)return ansans1 = dfs(root1, ans1)ans2 = dfs(root2, ans2)return ans1 == ans2

LCP44.开幕式焰火

DFS + 前序遍历 + set()

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def numColor(self, root: TreeNode) -> int:# DFS + 前序遍历 + set()s = set()def dfs(node, s):if node is None:returns.add(node.val)dfs(node.left, s)dfs(node.right, s)dfs(root, s)return len(s)

或者把s非重复字典,放到dfs函数外面,也可以实现这个逻辑。为什么?

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def numColor(self, root: TreeNode) -> int:# DFS + 前序遍历 + set()s = set()def dfs(node):if node is None:returns.add(node.val)dfs(node.left)dfs(node.right)dfs(root)return len(s)

两种方式区别在于 set 的定义位置与传递形式不同,效果一样是因为都利用 set 去重特性,遍历二叉树时添加节点值并最终返回其元素个数来统计不同节点值数量。

BFS + 层遍历 + 队列

层次遍历顺序:按照树的层次一层一层地向下遍历,直到队列为空。
这里地遍历顺序是广度优先地按层遍历,从根节点开始,每层从左到右一次访问节点。

# 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 Solution:def numColor(self, root):s = set()self.search(s, root)return len(s)def search(self, s, node):if node is None:returnq = []q.append(node)while q:current_node = q.pop(0)s.add(current_node.val)if current_node.left:q.append(current_node.left)if current_node.right:q.append(current_node.right)

404.左叶子之和

  • 返回所有左叶子值之和
  • 为了理解如何找到左叶子,先不完成这道题的要求,先写一个dfs来判断如何找到左叶子。

DFS写法

def (node, is_left):if node is None:return# 判断是否为左叶子节点if node.left is None and node.right is None and is_left:res.append(node.val)dfs(node.left, True)dfs(node.right, False)dfs(root, False)

BFS写法

class TreeNode:def __inti__(self, val=0, left=None, right=None):self.val = valself.right = rightself.left = leftclass Solution:def sumOfLeftLeaves(self, root):res = []if root is None:return resultq = []q.append((root, False))while q:current_node, is_left = q.pop(0)# 判断是否是左叶子节点if current_node.left is None and current_node.right is None and s_left:result.append(current_node.val)if current_node.left:q.append((current_node.left, True))if current_node.right:q.append((current_node.right, False))return result 			

以上是如何遍历左叶子的方法
下面完成本题任务,加和所有左叶子值

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:def sumOfLeftLeaves(self, root: Optional[TreeNode]) -> int:res = 0def dfs(node, is_left):nonlocal resif node is None:return# 关键逻辑,is_left递归决定是否dfsif node.left is None and node.right is None and is_left:res += node.valdfs(node.left, True)dfs(node.right, False)dfs(root, False)return res
一开始没加nonlocal一直通过不了!!
如果dfs函数内部没有用nonlocal声明res,python会认为在dfs内部重新定义了一个局部变量res,(尽管我实际上是想操作外层函数中的那个res),并且因为我在用res之前没有对这个新认为的局部变量进行初始化,所以会抛出unboundlocalerrro的错误,提示无法访问一个没有关联值的局部变量
当我加了nonlocal res后,就明确告诉了python解释器,在dfs函数中操作的res是来自外层函数的那个以及已经初始化过的局部变量,这样就能正确找到。

671.二叉树中第二小的节点

  • 这道题很难么?我认为只要检查根节点的左右子节点就行,如果根节点的左右子节点都相等,才需要递归检查左右子树,
  • 直到发现第一次不相等,不等于根节点那个值就是第二大的值,我这个思路对不对?

不对!!!

  1. 类比欧冠比赛来理解二叉树问题
    • 冠军(根节点最小值)的确定方式
      • 在欧冠比赛中,冠军是通过层层比赛筛选出来的最强队伍。在二叉树中,根节点的值被定义为左右子节点中的最小值(root.val = min(root.left.val, root.right.val)),这就好像冠军是从左右两个“分区”(左右子树)中选出的最小值一样。
    • 第二强队伍(第二小值)的复杂性
      • 在欧冠比赛中,亚军不一定是第二强的队伍。因为比赛的赛制是淘汰赛,可能有其他很强的队伍在和冠军队伍比赛前就被淘汰了,这些队伍也许比亚军更强。类比到二叉树中,只看根节点的左右子节点来确定第二小的值是不准确的。就像比赛中有很多队伍在淘汰赛过程中被淘汰一样,二叉树中的节点值也存在多种情况。
      • 例如,在二叉树中,即使根节点的左右子节点相等,在子树的更深处可能存在比根节点大,但比当前左右子节点小的值,这就好像在比赛中,有一些队伍虽然没有直接和冠军竞争,但实力介于冠军和我们最初认为的“亚军”(根节点左右子节点)之间。
    • 第二强队伍(第二小值)与冠军(根节点最小值)的关联
      • 你说的“第二强的一定和冠军交过手”类比到二叉树中,有一定的相似性。在二叉树中,真正的第二小的值一定是和根节点的值(最小的值)有比较关系的。它要么是根节点左右子节点中的较大值(如果存在差异),要么是在子树中比根节点值大的其他值。但不能简单地通过根节点左右子节点来判断,而是要遍历整个二叉树,就像要考虑整个欧冠比赛的所有队伍一样,来找到所有比根节点值大的节点值,然后从中确定第二小的值。
  2. 总结
    • 这个类比很形象地说明了不能简单地根据二叉树的局部结构(如根节点左右子节点)来确定第二小的值,而是要像考虑整个欧冠比赛的队伍情况一样,全面地考虑二叉树中所有节点的值,才能准确地找到第二小的值。

所以本质上这道题还是遍历

遍历 + set() + 排序
# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def findSecondMinimumValue(self, root: TreeNode) -> int:"""先序遍历+set"""s = set()def dfs(node):if not node:return           nonlocal ss.add(node.val)dfs(node.left)dfs(node.right)dfs(root)min1 = float('inf') # 最小min2 = float('inf') # 第二小# 则关键逻辑是找到s中有没有一个val,满足 min1 < val < min2 # 如果for val in s:if val < min1:     # 存在一个val比最小的min1还要小,就说明要更新min1为val,且更新min2为valmin2 = min1    # 更新min2min1 = val     # elif val < min2 :  # val比min1大比min2小,就是第二大| 或者等于,也就是第二大的值!!!min2 = val     # min2已经更新为上一轮的min1了!,此时val就是第二大的min2!return -1 if min2 == float('inf') else min2       

另一种写法

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = Noneclass Solution:def findSecondMinimumValue(self, root: TreeNode) -> int:"""先序遍历"""def helper(root, val): # 当前要遍历的节点,用于比较的值val,调用的时候直接调用根节点值,也就是最小值!!!            if not root:     # 递归终止条件,到头return -1    # 这道题找值,这里应该返回值,有的题不返回值# 关键逻辑:val是要比较的值,root.val是当前节点的值if root.val > val:# 当前节点值大于参考值,当前值有可能是!!第二小!!return root.val# 递归遍历左右子树,且传入当前节点值作为参考# 如果走到头都没有发现比val大的,返回-1表示这条路不存在left = helper(root.left, val)  # 注意这里val!并没有在每次递归时改变!!right = helper(root.right, val) # !val始终时根节点,也就是最小!!# 处理左右子树返回的结果!如果某个子树返回的值是-1,即到头没发现第二小!就返回另一边树的值if left < 0:return rightif right < 0:return left# 如果左右都有返回值,小的才是我们要找的第二小!return min(left, right)return helper(root, root.val)    
  1. 定义辅助函数
    • 定义 helper 函数,接受当前节点 root 和参考值 val(初始为根节点值)。
  2. 递归遍历与判断
    • 若当前节点为空,返回 -1。
    • 若当前节点值大于参考值,返回该节点值(可能是第二小值)。
    • 递归遍历左右子树,获取左右子树中可能的第二小值 leftright
  3. 处理子树返回结果
    • left 小于0,返回 right;若 right 小于0,返回 left;若都大于等于0,返回 min(left, right)
  4. 最终调用
    • 外部调用 helper 函数从根节点开始遍历二叉树,返回最终找到的第二小值(若不存在则为 -1)。

总的来说,这段代码通过深度优先搜索(DFS)的方式递归地遍历二叉树,在遍历过程中根据节点值与参考值的比较以及左右子树的返回结果来逐步确定可能的第二小的值,直到遍历完整个二叉树得出最终答案。

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

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

相关文章

远程控制软件:探究云计算和人工智能的融合

在数字化时代&#xff0c;远程控制工具已成为我们工作与生活的重要部分。用户能够通过网络远程操作和管理另一台计算机&#xff0c;极大地提升了工作效率和便捷性。随着人工智能&#xff08;AI&#xff09;和云计算技术的飞速发展&#xff0c;远程控制工具也迎来了新的发展机遇…

腾讯云 AI 代码助手:产品研发过程的思考和方法论

一、文章摘要 本文将详细阐述 腾讯云 AI 代码助手的历史发展形态与产品整体架构&#xff0c;并从技术、研发方法论的角度分别阐述了产品的研发过程。 全文阅读约 5&#xff5e;8 分钟。 二、产品布局 AI 代码助手产品经历了三个时代的发展 第一代诸如 Eclipse、Jetbrains、V…

Qt实现窗口内的控件自适应窗口大小

前言&#xff1a;因为有时候窗口内的控件比较大&#xff0c;但是为了同时操作多个窗口&#xff0c;希望可以根据情况&#xff0c;在调整窗口大小时&#xff0c;控件能自适应大小&#xff0c;于是通过遍历整个界面内的控件&#xff0c;并在调整大小的事件中按比率调整控件大小实…

WebGIS技术汇总

WebGIS系统通常都围绕地图进行内容表达&#xff0c;但并不是有地图就一定是WebGIS&#xff0c;所以有必要讨论下基于Web的地图API分类及应用场景。 Web上的Map API主要分类如下几类&#xff1a; Charts&#xff1a;以D3.js&#xff0c;Echarts等为代表。LBS&#xff1a;以高德…

sql server 获取当前日期的时间戳

SQL Server 获取当前日期的时间戳 在 SQL Server 中&#xff0c;可以使用 GETDATE() 函数获取当前日期和时间。如果想要获取当前日期的时间戳&#xff0c;可以将日期转换为 UNIX 时间戳格式。本文将介绍如何在 SQL Server 中获取当前日期的时间戳&#xff0c;并提供示例代码。 …

Java与C#

Java和C#&#xff08;C Sharp&#xff09;是两种流行的面向对象编程语言&#xff0c;它们在很多方面非常相似&#xff0c;因为它们都受到了类似的编程范式和语言设计理念的影响。然而&#xff0c;它们之间也存在一些重要的区别。 平台依赖性&#xff1a; Java&#xff1a;Java是…

Oracle 深入学习 Part 9: Storage Structure and Relationships(存储结构与关系)

在数据库管理系统&#xff08;DBMS&#xff09;中&#xff0c;Segment&#xff08;段&#xff09;、Extent&#xff08;区块&#xff09; 和 Block&#xff08;块&#xff09; 是描述数据库物理存储结构的三个重要概念。这些概念帮助理解数据库是如何在磁盘等存储设备上组织和管…

活着就好20241127

今天是27号&#xff0c;周三&#xff0c;一个承前启后并积蓄力量的日子。亲爱的朋友们&#xff0c;大家早上好&#xff01;在度过了周二这个巩固成果、深化努力的阶段后&#xff0c;我们迎来了又一个充满挑战与机遇的周三。周三&#xff0c;作为一周的转折点&#xff0c;是我们…

C语言实例之10求0-200内的素数

1. 素数 素数&#xff08;Prime number&#xff09;&#xff0c;也叫质数&#xff0c;是指在大于 1 的自然数中&#xff0c;除了 1 和它自身外&#xff0c;不能被其他自然数整除的数。例如 2、3、5、7、11 等都是素数&#xff0c;而 4 能被 2 整除、6 能被 2 和 3 整除&#x…

区块链知识体系

1. 区块链基础知识 Q: 什么是区块链&#xff1f; A: 区块链是一种去中心化的分布式账本技术&#xff0c;通过加密算法保证数据的不可篡改性和透明性。它由一系列按时间顺序链接的区块组成&#xff0c;每个区块包含一批交易记录。 Q: 区块链的主要特点是什么&#xff1f; 去…

使用Python和Pybind11调用C++程序(CMake编译)

目录 一、前言二、安装 pybind11三、编写C示例代码四、结合Pybind11和CMake编译C工程五、Python调用动态库六、参考 一、前言 跨语言调用能对不同计算机语言进行互补&#xff0c;本博客主要介绍如何实现Python调用C语言编写的函数。 实验环境&#xff1a; Linux gnuPython3.10…

哈希C++

文章目录 一.哈希的概念1.直接定址法2.负载因子 二.哈希函数1.除法散列法 / 除留余数法2.乘法散列法3.全域散列法&#xff08;了解&#xff09; 三.处理哈希冲突哈希冲突&#xff1a;1.开放定址法&#xff08;1&#xff09;线性探测&#xff1a;&#xff08;2&#xff09;二次探…

SAR ADC系列15:基于Vcm-Base的开关切换策略

VCM-Based开关切换策略&#xff1a;采样~第一次比较 简单说明: 电容上下极板分别接Vcm&#xff08;一般Vcm1/2Vref&#xff09;。采样断开瞬间电荷锁定&#xff0c;进行第一次比较。 当VIP > VIN 时&#xff0c;同时 减小VIP 并 增大VIN 。P阵列最高权重电容从Vcm(1/2Vref)…

深度学习模型:循环神经网络(RNN)

一、引言 在深度学习的浩瀚海洋里&#xff0c;循环神经网络&#xff08;RNN&#xff09;宛如一颗独特的明珠&#xff0c;专门用于剖析序列数据&#xff0c;如文本、语音、时间序列等。无论是预测股票走势&#xff0c;还是理解自然语言&#xff0c;RNN 都发挥着举足轻重的作用。…

网络--传输层协议--UDP

传输层作用:负责数据能够从发送端传输到接收端。 1、再谈端口号 端口号标识了一个主机上进行通信的不同的应用程序。 1.1、端口号划分范围 0 - 1023 : 知名端口号,HTTP、FTP、SSH等这些广为使用的应用层协议,他们的端口号都是固定的。 10234 - 65536:操作系统动态分配的…

【IEEE独立出版 | 厦门大学主办】第四届人工智能、机器人和通信国际会议(ICAIRC 2024,12月27-29日)

第四届人工智能、机器人和通信国际会议&#xff08;ICAIRC 2024&#xff09; 2024 4th International Conference on Artificial Intelligence, Robotics, and Communication 重要信息 会议官网&#xff1a;www.icairc.net 三轮截稿时间&#xff1a;2024年11月30日23:59 录…

vue的理解

什么是vue vue是一套用于构建用户界面的渐进式框架&#xff0c;与其他框架不同的是&#xff0c;vue被设计为可以自底向上逐层应用&#xff0c;它也是创建单页面应用的web应用框架。vue的核心库只关注视图层&#xff0c;不仅易上手&#xff0c;还便于与第三方库或既有项目整合。…

第十六届蓝桥杯模拟赛第二期题解—Java

第十六届蓝桥杯模拟赛/校赛第二期个人题解&#xff0c;有错误的地方欢迎各位大佬指正 问题一(填空题) 【问题描述】 如果一个数 p 是个质数&#xff0c;同时又是整数 a 的约数&#xff0c;则 p 称为 a 的一个质因数。 请问&#xff0c; 2024 的最大的质因数是多少&#xff1f; …

二代三代社保卡读卡器串口命令协议,适用于单片机等嵌入式系统使用

接触读社保卡&#xff1a;EA EB EC ED 04 00 7E 7A BB 非接读社保卡&#xff1a;EA EB EC ED 04 00 2E 2A BB 返回格式数据&#xff1a; EAEBECED长度信息类型域状态数据校验BB 例如&#xff1a; EA EB EC ED 57 00 00 7E 7B 22 6E 61 6D 65 22 3A 22 D5 C5 CE AC B1 A6 2…

CLIP-Adapter: Better Vision-Language Models with Feature Adapters

当前的问题 由于CLIP的过度参数化和缺乏足够的训练样例&#xff0c;简单的微调会导致对特定数据集的过拟合&#xff0c;并且训练过程会非常缓慢由于在所有CLIP层之间的向前和向后传播。 方法 视觉适配器 A v ( ⋅ ) A_v(\cdot) Av​(⋅)(包含 W 1 v , W 2 v \textbf{W}^v_1,\…