二叉树层序遍历(广度优先搜索)基础概念与经典题目(Leetcode题解-Python语言)

二叉树的广度优先搜索即从上到下、从左到右地进行搜索,对于层序遍历(Level Order)问题,即依次遍历第一层节点、第二层节点…等,基本可以秒杀。

广度优先搜索是通过队列来实现的,python中优先用collections.deque,因为deque的 popleft() 比列表的 pop(0) 快不少。

剑指 Offer 32 - I. 从上到下打印二叉树

import collections  # leetcode里面可以去掉,下面都省略
class Solution:def levelOrder(self, root: TreeNode) -> List[int]:ans = list()if not root:return ansqueue = collections.deque()queue.append(root)while queue:node = queue.popleft()ans.append(node.val)if node.left:  # 左子节点非空,加入队列queue.append(node.left)if node.right:  # 右子节点非空,加入队列queue.append(node.right)return ans

从根节点开始,每个节点入队之后,在出队的时候把它的左右子节点也入队(如果非空),则该队列就完成了广度优先搜索。

102. 二叉树的层序遍历 (剑指 Offer 32 - II. 从上到下打印二叉树 II)

class Solution:def levelOrder(self, root: TreeNode) -> List[List[int]]:ans = list()if not root:   # 判断空树return ansqueue = collections.deque()queue.append(root)while queue:curLevel = list()for i in range(len(queue)):node = queue.popleft()curLevel.append(node.val)if node.left:  # 左子节点非空,加入队列queue.append(node.left)if node.right:  # 右子节点非空,加入队列queue.append(node.right)ans.append(curLevel)return ans

需要把同一层的节点放到同一个数组中,方法是用一个当前层数组 curLevel,通过循环每次把同一层的节点的子节点全部入队,同时将这些节点的值记录到curLevel 中,一层节点遍历完之后将 curLevel 加入结果数组 ans 中。

103. 二叉树的锯齿形层序遍历(剑指 Offer 32 - III. 从上到下打印二叉树 III)

class Solution:def levelOrder(self, root: TreeNode) -> List[List[int]]:ans = list()if not root:   # 判断空树return ansqueue = collections.deque()queue.append(root)odd = True # 奇偶层标志while queue:curLevel = list()for i in range(len(queue)):node = queue.popleft()curLevel.append(node.val)if node.left:  # 左子节点非空,加入队列queue.append(node.left)if node.right:  # 右子节点非空,加入队列queue.append(node.right)if odd:ans.append(curLevel)odd = Falseelse:ans.append(curLevel[::-1])odd = Truereturn ans

按照之字形顺序打印二叉树,只需要加个奇偶层标志即可。

1609. 奇偶树

class Solution:def isEvenOddTree(self, root: Optional[TreeNode]) -> bool:if not root:   # 判断空树return anslevel = 0queue = collections.deque()queue.append(root)while queue:curLevel = []for i in range(len(queue)):node = queue.popleft()if (level % 2 == 0 and node.val % 2 == 0) or (level % 2 != 0 and node.val % 2 != 0):return Falseelse:if len(curLevel) == 0:curLevel.append(node.val)elif (level % 2 == 0 and node.val <= curLevel[-1]) or (level % 2 != 0 and node.val >= curLevel[-1]):return FalsecurLevel.append(node.val)if node.left:  # 左子节点非空,加入队列queue.append(node.left)if node.right:  # 右子节点非空,加入队列queue.append(node.right)level += 1return True

根据所在层数的奇偶,判断节点值的奇偶以及递增或递减是否符合奇偶树的要求。

107. 二叉树的层序遍历 II

class Solution:def levelOrderBottom(self, root: TreeNode) -> List[List[int]]:ans = list()if not root:return ansqueue = collections.deque()queue.append(root)while queue:curLevel = list()for i in range(len(queue)):node = queue.popleft()curLevel.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)ans.append(curLevel)return ans[::-1]

唯一区别就是输出结果时倒转输出。

226. 翻转二叉树

class Solution:def invertTree(self, root: TreeNode) -> TreeNode:if not root:returnqueue = collections.deque()queue.append(root)while queue:for _ in range(len(queue)):node = queue.popleft()node.left, node.right = node.right, node.leftif node.left:queue.append(node.left)if node.right:queue.append(node.right)return root

层序遍历时,交换节点的左右子节点,就完成了翻转二叉树,用前中后序遍历的写法见这篇文章。

104. 二叉树的最大深度

class Solution:def maxDepth(self, root: Optional[TreeNode]) -> int:if not root:return 0queue = collections.deque()queue.append(root)depth = 0while queue:depth += 1for _ in range(len(queue)):node = queue.popleft()if node.left:queue.append(node.left)if node.right:queue.append(node.right)return depth

二叉树的最大深度,就是二叉树的层数。

111. 二叉树的最小深度

class Solution:def minDepth(self, root: TreeNode) -> int:if not root:return 0queue = collections.deque()queue.append(root)depth = 1while queue:for i in range(len(queue)):node = queue.popleft()if not node.left and not node.right:return depthif node.left:  # 左子节点非空,加入队列queue.append(node.left)if node.right:  # 右子节点非空,加入队列queue.append(node.right)depth += 1

只需要用depth记录层数,当遇到叶节点就返回depth,即为最小深度。

199. 二叉树的右视图

class Solution:def rightSideView(self, root: TreeNode) -> List[int]:ans = list()if not root:return ansqueue = collections.deque()queue.append(root)while queue:n = len(queue)for i in range(n):node = queue.popleft()if i == n - 1:ans.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)return ans

结果需要的是每一层的最右边的数,因此循环到最右边的数时,才将节点加入结果数组 ans。

513. 找树左下角的值

class Solution:def findBottomLeftValue(self, root: TreeNode) -> int:if not root:return 0queue = collections.deque()queue.append(root)while queue:curLevel = list()for i in range(len(queue)):node = queue.popleft()curLevel.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)return curLevel[0]

结果需要的是最底层的最左边节点的值,因此用curLevel数组记录每层的节点值,最后返回curLevel[0]就是最底层的最左边节点的值。

1302. 层数最深叶子节点的和

class Solution:def deepestLeavesSum(self, root: Optional[TreeNode]) -> int:# 题目说了非空树queue = collections.deque()queue.append(root)while queue:curLevel = 0for i in range(len(queue)):node = queue.popleft()curLevel += node.valif node.left:queue.append(node.left)if node.right:queue.append(node.right)return curLevel

返回最后一层的节点之和。

637. 二叉树的层平均值

class Solution:def averageOfLevels(self, root: TreeNode) -> List[float]:ans = list()if not root:return ansqueue = collections.deque()queue.append(root)while queue:currLevel = list()n = len(queue)for i in range(n):node = queue.popleft()currLevel.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)ans.append(mean(currLevel))return ans

结果需要的是每一层的平均数,因此将平均数加入结果数组 ans。

515. 在每个树行中找最大值

class Solution:def largestValues(self, root: TreeNode) -> List[int]:ans = list()if not root:return ansqueue = collections.deque()queue.append(root)while queue:currLevel = list()n = len(queue)for i in range(n):node = queue.popleft()currLevel.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)ans.append(max(currLevel))return ans

结果需要的是每一层的最大数,因此将最大数加入结果数组 ans。

1161. 最大层内元素和

class Solution:def maxLevelSum(self, root: TreeNode) -> int:if not root:return 0queue = collections.deque()queue.append(root)MaxValue = -float('inf')ans = 1depth = 1while queue:curLevel = 0for i in range(len(queue)):node = queue.popleft()curLevel += node.valif node.left:queue.append(node.left)if node.right:queue.append(node.right)if curLevel > MaxValue:MaxValue = curLevelans = depthdepth += 1return ans

目标是找到层值之和最大的那一层,记录层数和最大值即可,注意 MaxValue 初始值要设成负无穷 -float(‘inf’) 。

429. N 叉树的层序遍历

"""
# Definition for a Node.
class Node:def __init__(self, val=None, children=None):self.val = valself.children = children
"""
import collections
class Solution:def levelOrder(self, root: 'Node') -> List[List[int]]:ans = list()if not root:return ansqueue = collections.deque()queue.append(root)while queue:curLevel = list()for i in range(len(queue)):node = queue.popleft()curLevel.append(node.val)for child in node.children: # 区别if child:queue.append(child)ans.append(curLevel)return ans

N叉数是 children 列表而二叉树是 left 和 right ,遍历 children 即可。

116. 填充每个节点的下一个右侧节点指针

class Solution:def connect(self, root: 'Node') -> 'Node':if not root:return rootqueue = collections.deque()queue.append(root)while queue:size = len(queue)for i in range(size):node = queue.popleft()if i < size - 1: # 必须使用 sizenode.next = queue[0]if node.left:queue.append(node.left)if node.right:queue.append(node.right)return root

层序遍历一次二叉树,记录节点是队列先进先出的,所以左边的节点先出来,它的 next 就为 queue[0],注意 len(queue) 是会变化的,所以必须使用 size 记录一层的长度

117 . 填充每个节点的下一个右侧节点指针 II

class Solution:def connect(self, root: 'Node') -> 'Node':if not root:return rootqueue = collections.deque()queue.append(root)while queue:size = len(queue)for i in range(size):node = queue.popleft()if i < size - 1:node.next = queue[0]if node.left:queue.append(node.left)if node.right:queue.append(node.right)return root

不完美的二叉树,但是和上一题一模一样的代码。

623. 在二叉树中增加一行

class Solution:def addOneRow(self, root: TreeNode, val: int, depth: int) -> TreeNode:if depth == 1:new_root = TreeNode(val = val, left = root, right = None)return new_rootqueue = collections.deque()queue.append((root, 1))while queue:for _ in range(len(queue)):node, d = queue.popleft()if d == depth - 1:old_left = node.leftold_right = node.rightnode.left = TreeNode(val = val, left = old_left, right = None)node.right = TreeNode(val = val, left = None, right = old_right)else:if node.left:queue.append((node.left, d+1))if node.right:queue.append((node.right, d+1))return root

如果在第一行增加,那就是创建一个新的根节点,然后将原根节点作为左子节点。否则的话,就在队列中使用多一个参数 d 来记录深度,在 d - 1 层进行增加一行的操作,先记住节点原来的左右子节点 old_left 与 old_right,然后创建新的节点即可。关键是必须使用 for 循环,对整个第 d - 1 层都进行同样的操作。

662. 二叉树最大宽度

class Solution:def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int:ans = 1if not root:return 0queue = collections.deque()queue.append((root, 1))while queue:cur = []for _ in range(len(queue)):node, pos = queue.popleft()cur.append(pos)if node.left:queue.append((node.left, 2 * pos - 1))if node.right:queue.append((node.right, 2 * pos))if max(cur) - min(cur) + 1 > ans:ans = max(cur) - min(cur) + 1return ans

在队列中使用多一个参数 pos 来记录位置,只需要记住的是,位置为 pos 的节点(从 1 开始)的左子节点位置是 2 * pos - 1,右子节点的位置是 2 * pos。

958. 二叉树的完全性检验

class Solution:def isCompleteTree(self, root: TreeNode) -> bool:queue = collections.deque()queue.append((root, 1))depth = 0while queue:if len(queue) == 2**depth:for i in range(len(queue)):node, pos = queue.popleft()if node.left:queue.append((node.left, pos*2-1))if node.right:queue.append((node.right, pos*2))depth += 1else:for i in range(len(queue)):node, pos = queue.popleft()if node.left or node.right or (i+1) != pos:return Falsereturn True

与上一题类似的,关键是记录节点的位置(注意位置从 1 开始)。在满层中正常遍历,一旦遇到不满的层,如果其中有非叶子节点或者位置对不上则不是完全二叉树。

993. 二叉树的堂兄弟节点

class Solution:def isCousins(self, root: TreeNode, x: int, y: int) -> bool:# x 和 y 的深度与父节点x_depth, x_parent, y_depth, y_parent = None, None, None, None level = 0queue = collections.deque([(root, None)])while queue:n = len(queue)level += 1for i in range(n):node, node_parent = queue.popleft()# 每个节点的值都是唯一的if node.val == x:x_depth = levelx_parent = node_parentif node.val == y:y_depth = levely_parent = node_parentif node.left:queue.append((node.left, node))if node.right:queue.append((node.right, node))return x_depth == y_depth and x_parent != y_parent

由于题目中说明每个节点的值都是唯一的,所以用四个变量分别表示 x 和 y 的深度与父节点。然后在队列中要同时记录节点和节点的父节点,如果遇到值为 x 或 y 的节点就记录其深度和父节点,最后进行比较即可。

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

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

相关文章

leetcode049. 最后一块石头的重量 II

一:题目 二:上码 class Solution { public:/**思路:1.分析题意只要我们将石头分为尽可能相同的两堆,他们的重量相减后剩余的重量就是最小。 物品的重量为stones[i];物品的价值也为stone[i];temp代表总重量的一半那么我们最终得到的stones[temp]:就是背包容量为temp的最大重量为…

大改革,GNOME 3.x将直接跳到GNOME 40

GNOME 3.38 发布后&#xff0c;GNOME 基金会宣布了用于 GNOME 的新版本控制方案&#xff0c;将于2021年3月发布的下一版 GNOME 将是 GNOME 40。你没看错&#xff0c;版本号直接从现在的 3.x 跳到了 40。以 GNOME 40 为例&#xff0c;其开发周期将包含三个阶段&#xff0c;对应的…

从前中后序遍历构造二叉树,三题无脑秒杀

如果只是前中后序遍历的其中一种&#xff0c;是不可能唯一确定一个二叉树的&#xff0c;必须是其中两个的结合&#xff0c;由此便产生了三道题目&#xff0c;在这里可以全部秒杀。 需要记住的要点是&#xff1a; 前序&#xff08;根左右&#xff09;——第一个节点一定是根节点…

.NET Core + Kubernetes:StatefulSet

在 Kubernetes 中&#xff0c;Pod 资源的控制器 Deployment、Replicaset、Daemonset 等常用于管理无状态应用&#xff0c;它们所管理的 Pod 对应的 IP、名字&#xff0c;启停顺序等都是随机的&#xff0c;Pod 之间也并不存在任何关联关系。而实际情况下&#xff0c;在应用集群部…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之上——原理与设计

哈希表&#xff08;Hash table&#xff0c;也叫散列表&#xff09;&#xff0c;是根据键&#xff08;Key&#xff09;而直接访问数据在内存中的储存位置&#xff08;又叫做存储桶&#xff0c;Buckets&#xff09;的数据结构。也就是说&#xff0c;它通过计算一个关于键值的函数…

python编程中的小问题汇总

前言 本文记录了我在python编程中遇到的各种小问题&#xff0c;持续更新。 1. x x 1 VS x 1 辨析下面这两段代码&#xff1a; >>> x y [1, 2, 3, 4] >>> x [4] >>> x [1, 2, 3, 4, 4] >>> y [1, 2, 3, 4, 4]>>> x y …

都在讨论高并发,结果连并发量、TPS、QPS都分不清

“ 年年岁岁跳槽季&#xff0c;回回必问高并发&#xff01;原因很简单&#xff0c;因为高并发能牵扯出太多问题&#xff0c;接口响应超时、CPU负载升高、GC频繁、死锁、大数据量存储等&#xff0c;能考察求职者的真实情况。而很多人在第一步就倒下了&#xff01;因为对数据化的…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之中——实际应用

上一节介绍了哈希表的原理与设计方法&#xff0c;这一节则直接python中现有的哈希表类型&#xff1a;哈希集合 set&#xff08;集合&#xff09;和哈希映射 dict&#xff08;字典&#xff09;来解决实际应用&#xff08;刷题&#xff09;。 零、概念 在介绍实际应用之前&#…

leetcode518. 零钱兑换 II

一:题目 二:上码 class Solution { public:/**思路:1.分析题意这个满足答案的结果有很多种&#xff0c;所以我们可以用动态规划去做,那么题意中我们可以知道的是我们是可以输入一种面值的时候,我们是可以重复输入的&#xff0c;那么这就是背包类型中的完全背包了2.动态规划5步…

跟我一起学.NetCore之选项(Options)核心类型简介

前言.NetCore中提供的选项框架&#xff0c;我把其理解为配置组&#xff0c;主要是将服务中可供配置的项提取出来&#xff0c;封装成一个类型&#xff1b;从而服务可根据应用场景进行相关配置项的设置来满足需求&#xff0c;其中使用了依赖注入的形式&#xff0c;使得更加简单、…

哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之下——设计键

在很多应用中&#xff0c;我们会发现某种映射关系&#xff08;模式&#xff09;&#xff0c;但它并不是简单一 一对应的。这时&#xff0c;我们就要从键 key 入手&#xff0c;通过设计合适的键&#xff0c;建立映射关系。leetbook的这个章节总结了一些常见的键&#xff0c;以供…

《ASP.NET Core项目开发实战入门》送书活动结果公布

截至2020.09.20 本次送书活动《ASP.NET Core项目开发实战入门》。下面把Top 5的留言截图给大家回顾一下。以下5位同学将获赠书籍一本&#xff1a;小林子鉴静红脸先生阿星Plus以上同学请在2020年9月25日24&#xff1a;00之前加小二微信领取赠书&#xff0c;超过时间视为放弃。小…

二分查找基础概念与经典题目(Leetcode题解-Python语言)二分索引型

二分查找的定义如下&#xff08;引自Wiki&#xff09;&#xff1a; 在计算机科学中&#xff0c;二分查找算法&#xff08;英语&#xff1a;binary search algorithm&#xff09;&#xff0c;也称折半搜索算法&#xff08;英语&#xff1a;half-interval search algorithm&…

Magicodes.IE 2.3重磅发布——.NET Core开源导入导出库

在2.3这一版本的更新中&#xff0c;我们迎来了众多的使用者、贡献者&#xff0c;在这个里程碑中我们也添加并修复了一些功能。对于新特点的功能我将在下面进行详细的描述&#xff0c;当然也欢迎更多的人可以加入进来&#xff0c;再或者也很期待大家来提issues或者PR&#xff0c…

听说用 C# 写 TensorFlow 更高效?

经过半年呕心沥血的努力&#xff0c;SciSharp STACK终于把Tensorflow .NET绑定升级到可以使用 tensorflow 2.3, 新版本最大的优势是实现了Eager模式, 这个特性是让.NET C#/ F#成为机器学习模型开发工具的重要前置条件。NugGet包下载:https://www.nuget.org/packages/TensorFlow…

leetcode279. 完全平方数

一:题目 二:上码 class Solution { public:/**思路:1.分析题意这个就是将一个数分成几个数的和;然而的话,这几个数必须的是完全平方数,我们要求的是最少数量的完全平方数这个满足答案的有好几个;但是我们要求的是最少的数量2.动态规划五步走1>:确定dp数组的含义以及下标的含…

岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)

695. 岛屿的最大面积 先上最经典的题目&#xff0c;详细思路看这题的官方题解&#xff0c;简单来说的岛屿问题就是遍历二维数组&#xff0c;一般都是从一块陆地开始&#xff0c;进行深度优先或者广度优先搜索&#xff0c;每次上下左右四个方向选其一然后寻找下一块陆地&#x…

跟我一起学.NetCore之Options实例演示及分析

前言来啦&#xff01;来啦&#xff01;上一节一堆代码&#xff0c;是不是感觉甚是无味啊&#xff1f;没关系&#xff0c;这里结合上一节内容专注举例演示&#xff0c;绝不废话&#xff01;走起~~~~~正文老规矩&#xff0c;一个WebApi项目走起&#xff0c;项目结构如下&#xff…

leetcode139. 单词拆分

一:题目 二:上码 class Solution { public:/**思路:1.分析题意单词就是物品;字符串就是背包;单词能否组成字符串就是在问,物品能不能将背包装满单词可以重复使用那么说明这是一个完全背包2.动态规划五步走1>:确定dp数组的与下标的含义&#xff08;这里用下标i是由我们的遍历…

二分查找基础概念与经典题目(Leetcode题解-Python语言)二分数值型

二分查找的讲解请见上一篇文章。本文主要记录对数值进行二分的题目解法与思路。 374. 猜数字大小 class Solution:def guessNumber(self, n: int) -> int:left 1right nwhile left < right:mid left (right - left) // 2if guess(mid) 1: # mid < pickleft mi…