二叉树层序遍历(广度优先搜索)基础概念与经典题目(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 的节点就记录其深度和父节点,最后进行比较即可。
二叉树层序遍历(广度优先搜索)基础概念与经典题目(Leetcode题解-Python语言)相关推荐
- 二叉树的遍历—广度优先(BFS)和深度优先(DFS)python实现
二叉树 二叉树(Binary tree)是树形结构的一个重要类型.对于二叉树的基础知识这里不做过多介绍,下面我们直接介绍二叉树的遍历方式和如何用python代码去实现二叉树的遍历. 二叉树的遍历(重点 ...
- 岛屿类问题的广度优先深度优先双解法(Leetcode题解-Python语言)
695. 岛屿的最大面积 先上最经典的题目,详细思路看这题的官方题解,简单来说的岛屿问题就是遍历二维数组,一般都是从一块陆地开始,进行深度优先或者广度优先搜索,每次上下左右四个方向选其一然后寻找下一块 ...
- 高度平衡的二叉搜索树基础概念与经典题目(Leetcode题解-Python语言)
高度平衡的二叉搜索树(平衡二叉树),定义见此Leetbook.简单来说,就是基于相同节点值构建出来的二叉搜索树中高度最小的,即为平衡二叉树(不唯一).有 N 个节点的平衡二叉搜索树,它的高度是 log ...
- 栈的基础概念与经典题目(Leetcode题解-Python语言)
栈是先入后出(后入先出)的数据结构,常用操作就 push 和 pop,Python中用列表实现即可,基本概念可以看Leetbook相关章节. 普通栈 232. 用栈实现队列 class MyQueue ...
- 二分查找基础概念与经典题目(Leetcode题解-Python语言)二分数值型
二分查找的讲解请见上一篇文章.本文主要记录对数值进行二分的题目解法与思路. 374. 猜数字大小 class Solution:def guessNumber(self, n: int) -> ...
- 哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之中——实际应用
上一节介绍了哈希表的原理与设计方法,这一节则直接python中现有的哈希表类型:哈希集合 set(集合)和哈希映射 dict(字典)来解决实际应用(刷题). 零.概念 在介绍实际应用之前,有一个概念我 ...
- 链表基础概念与经典题目(Leetcode题解-Python语言)
所谓链表,就是由链节点元素组成的表,那什么是链节点呢?直接上定义: class ListNode:def __init__(self, val=0, next=None):self.val = val ...
- 二分查找基础概念与经典题目(Leetcode题解-Python语言)二分索引型
二分查找的定义如下(引自Wiki): 在计算机科学中,二分查找算法(英语:binary search algorithm),也称折半搜索算法(英语:half-interval search algor ...
- 哈希表(散列表)基础概念与经典题目(Leetcode题解-Python语言)之下——设计键
在很多应用中,我们会发现某种映射关系(模式),但它并不是简单一 一对应的.这时,我们就要从键 key 入手,通过设计合适的键,建立映射关系.leetbook的这个章节总结了一些常见的键,以供参考. 4 ...
最新文章
- mysql数字字符串教程_很全面的mysql字符串函数的教程
- iOS获取已安装的app列表(私有库)+ 通过包名打开应用
- 开发函数计算的正确姿势 —— 移植 next.js 服务端渲染框架
- 2017.10.12 礼物(zjoi2011) 失败总结
- “腾讯持股比例提升”系误读!美团对外定增后腾讯持股比例降低
- 邮件服务器IMail教程(2)
- Win7 下安装流程图绘制软件 Dia
- ibus五笔快捷键 繁简 单字 词组切换
- 5种Python深度学习库和资料
- python3.6 scrapy模块查询POS后台获取指定时间和状态的订单存入到excel表格中
- linux 好书推荐
- 【Flutter】Dart 数据类型 布尔类型 ( 布尔类型定义 | 逻辑运算 )
- vue 引入 element-ui 报 es2015 的错
- (转)汇编bne的问题
- 阿里天池比赛——食物声音识别
- 《易中天中华史 - 第五卷 从春秋到战国》读书笔记
- 2022第三届全国大学生网络安全精英赛练习题(2)
- bochs linux 安装软件,bochs linux镜像
- OpenMV物品清单
- java打地鼠游戏教案,幼儿园打地鼠游戏教案
热门文章
- PHP开发常见功能实现流程
- PHP-高并发和大流量的解决方案
- 【遥感数字图像处理】实验:Erdas 软件的认识与使用
- Android之解决androidx.appcompat.widget.Toolbar去掉左边距
- 递归和非递归实现规律函数
- 关于nginx为站点绑定域名以及绑定多个域名
- 3500个常用汉字表_小学常用560个汉字笔画笔顺表,打印下来,小学六年慢慢练...
- html的canvas标签用法,html5中关于canvas标签用法(绘图)
- java爬虫工具xpath提取,2020-07-16--爬虫数据提取--xpath
- 那些年,画家发明的黑科技