二叉树的层序遍历
102. 二叉树的层序遍历
Given the root of a binary tree, return the level order traversal of its nodes' values. (i.e., from left to right, level by level).
Example 1:
Input: root = [3,9,20,null,null,15,7]
Output: [[3],[9,20],[15,7]]
Example 2:
Input: root = [1]
Output: [[1]]
Example 3:
Input: root = []
Output: []
Constraints:
- The number of nodes in the tree is in the range [0, 2000].
- -1000 <= Node.val <= 1000
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
res = []
queue = deque([root])
while queue:
tmp = []
for i in range(len(queue)):
node = queue.popleft()
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.left:
queue.append(node.right)
res.append(tmp)
return res
可以得到二叉树每层的节点值组成的列表,返回的是一个二维列表。其中用到了 Python 的 deque
双端队列数据结构。
具体的实现过程如下:
-
首先判断根节点是否为空,如果为空则直接返回空列表。
-
初始化结果列表
res
和双端队列queue
,并将根节点添加到队列中。 -
进入循环,当队列不为空时执行以下操作:
- 定义一个空列表
tmp
,用于存储当前层的节点值。 - 使用
for
循环遍历队列中当前层的节点,每次取出队列左侧的节点,并将其值添加到tmp
中。 - 如果当前节点有左子节点,则将左子节点添加到队列中。
- 如果当前节点有右子节点,则将右子节点添加到队列中。
- 将
tmp
添加到res
中。
- 定义一个空列表
-
返回结果列表
res
。
需要注意的是,在添加右子节点时,代码中写错了一个地方,应该是 if node.right:
,而不是 if node.left:
。
这段代码实现了一种常见的二叉树遍历方式,即层序遍历。它可以帮助我们更加直观地了解二叉树的结构,以及在某些场景下可以发挥比其他遍历方式更好的性能。
在这是用的python的deque,deque
和 queue
都提供了删除队列左侧元素的方法,但是它们的实现方式是不同的。
在 deque
中,使用 popleft()
方法来删除左侧元素,它的时间复杂度是 O(1),因为 deque
内部是使用双向链表实现的,所以在左侧弹出元素的操作是很快的。
而在 queue
中,使用 pop(0)
方法来删除左侧元素,它的时间复杂度是 O(n),因为 queue
内部是使用列表实现的,当删除左侧元素时,需要把整个列表向左移动一位,这个操作的时间复杂度是与列表长度 n 相关的。
所以,如果需要频繁地删除队列左侧的元素,建议使用 deque
。如果只是偶尔需要删除队列左侧的元素,使用 queue
也可以,但是要注意它的时间复杂度可能会影响性能。
扩展
103. 二叉树的锯齿形层序遍历
Given the root of a binary tree, return the zigzag level order traversal of its nodes' values. (i.e., from left to right, then right to left for the next level and alternate between).
Example 1:
Input: root = [3,9,20,null,null,15,7]
Output: [[3],[20,9],[15,7]]
Example 2:
Input: root = [1]
Output: [[1]]
Example 3:
Input: root = []
Output: []
Constraints:
- The number of nodes in the tree is in the range [0, 2000].
- -100 <= Node.val <= 100
这题和上一题代码就是多了一个even
判断当前是奇数还是偶数。
函数zigzagLevelOrder
接受一个二叉树作为输入,并返回一个列表,其中每个子列表表示二叉树的一个层次。列表中的每个子列表都按照锯齿形遍历的方式填充,即在偶数层上从左到右遍历,在奇数层上从右到左遍历。该函数使用一个队列来按照层次遍历二叉树,同时使用一个标志变量来确定当前层是奇数层还是偶数层。
# 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 zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
res = []
queue = deque([root])
even = False
while queue:
tmp = []
for i in range(len(queue)):
node = queue.popleft()
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(tmp[::-1] if even else tmp)
even = not even
return res
实现过程如下:
-
首先判断输入的根节点是否为空。如果为空,则直接返回空列表。
-
创建一个双端队列
queue
,并将根节点加入队列中。 -
创建一个布尔变量
even
,表示当前遍历的层数是否是偶数层。初始值为False
。 -
使用循环遍历队列
queue
中的所有节点:- 对于每个节点,将其值添加到临时列表
tmp
中,并将其左右子节点加入队列中。 - 遍历完当前层的所有节点后,将临时列表
tmp
加入到结果列表res
中。如果当前层为偶数层,则将tmp
列表翻转后再加入res
中。 - 切换布尔变量
even
的值,以便在下一层遍历时按照相反的顺序排列节点值。
- 对于每个节点,将其值添加到临时列表
-
返回结果列表
res
。
513. 找树左下角的值
Given the root of a binary tree, return the leftmost value in the last row of the tree.
Example 1:
Input: root = [2,1,3]
Output: 1
Example 2:
Input: root = [1,2,3,4,null,5,6,null,null,7]
Output: 7
Constraints:
- The number of nodes in the tree is in the range .
这个写起来就更简单了,不需要遍历,只保留底层最左边的结点,那直接把从左到右层序遍历,变为从右到左层序遍历即可,也就是
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
换成
if node.right:
queue.append(node.right)
if node.left:
queue.append(node.left)
完整代码
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
queue = deque([root])
while queue:
node = queue.popleft()
if node.right:
queue.append(node.right)
if node.left:
queue.append(node.left)
res = node.val
return res
实现过程如下:
-
创建一个双端队列
queue
,并将根节点加入队列中。 -
循环遍历队列
queue
中的所有节点,每次取出队列中的第一个节点:- 如果该节点的右子节点不为空,则将右子节点加入队列中。
- 如果该节点的左子节点不为空,则将左子节点加入队列中。
- 记录当前节点的值为结果
res
。
-
遍历完整棵树后,返回结果
res
即可。
199. 二叉树的右视图
给定一个二叉树的 根节点 root
,想象自己站在它的右侧,按照从顶部到底部的顺序,返回从右侧所能看到的节点值。
示例 1:
输入: [1,2,3,null,5,null,4]
输出: [1,3,4]
示例 2:
输入: [1,null,3]
输出: [1,3]
示例 3:
输入: []
输出: []
提示:
- 二叉树的节点个数的范围是
[0,100]
-100 <= Node.val <= 100
还是层序遍历,最右边的视图也就是层序遍历每层的最后一个节点。
写法1:
这里是用的tmp[-1]
,比较好理解,每层遍历之后的最后一个节点值。
# 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 rightSideView(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
res = []
queue = deque([root])
while queue:
tmp = []
for i in range(len(queue)):
node = queue.popleft()
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(tmp[-1])
return res
简化版的代码如下,结果也是对的,node在每次for循环之后也是指向当前层最后一个节点的,所以直接用node.val
也是对的。
# 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 rightSideView(self, root: Optional[TreeNode]) -> List[int]:
if not root:
return []
res = []
queue = deque([root])
while queue:
for i in range(len(queue)):
node = queue.popleft()
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(node.val)
return res
实现过程如下:
-
首先判断输入的根节点是否为空。如果为空,则直接返回空列表。
-
创建一个空列表
res
和一个双端队列queue
,并将根节点加入队列中。 -
使用循环遍历队列
queue
中的所有节点:- 对于每个节点,将其左右子节点加入队列中。
- 当遍历到每层的最后一个节点时,将该节点的值加入结果列表
res
中。
-
遍历完整棵树后,返回结果列表
res
即可。
116/117. 填充每个节点的下一个右侧节点指针
116. 填充每个节点的下一个右侧节点指针 - 力扣(Leetcode)
117. 填充每个节点的下一个右侧节点指针 II - 力扣(Leetcode)
给定一个二叉树:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL
。
初始状态下,所有 next 指针都被设置为 NULL
。
示例 1:
输入:root = [1,2,3,4,5,null,7] 输出: [1,#,2,3,#,4,5,7,#] 解释: 给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化输出按层序遍历顺序(由 next 指针连接),'#' 表示每层的末尾。
示例 2:
输入: root = [] 输出: []
提示:
- 树中的节点数在范围
[0, 6000]
内 -100 <= Node.val <= 100
进阶:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序的隐式栈空间不计入额外空间复杂度。
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return
queue = deque([root])
while queue:
l = len(queue)
for i in range(l):
node = queue.popleft()
if i != l-1:
node.next = queue[0]
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return root
实现过程如下:
-
首先判断输入的根节点是否为空。如果为空,则直接返回空值。
-
创建一个双端队列
queue
,并将根节点加入队列中。 -
使用循环遍历队列
queue
中的所有节点:- 对于每个节点,如果它不是该层的最后一个节点,则将该节点的
next
指针指向该层的下一个节点,即队列中的第一个节点。 - 将该节点的左右子节点加入队列中。
- 对于每个节点,如果它不是该层的最后一个节点,则将该节点的
-
遍历完整棵树后,返回原始的根节点即可。
637. 二叉树的层平均值
给定一个非空二叉树的根节点 root
, 以数组的形式返回每一层节点的平均值。与实际答案相差 10-5
以内的答案可以被接受。
示例 1:
输入: root = [3,9,20,null,null,15,7]
输出: [3.00000,14.50000,11.00000]
解释: 第 0 层的平均值为 3,第 1 层的平均值为 14.5,第 2 层的平均值为 11 。
因此返回 [3, 14.5, 11] 。
示例 2:
输入: root = [3,9,20,15,7]
输出: [3.00000,14.50000,11.00000]
提示:
- 树中节点数量在
[1, 104]
范围内 -231 <= Node.val <= 231 - 1
class Solution:
def averageOfLevels(self, root: Optional[TreeNode]) -> List[float]:
res = []
queue = deque([root])
while queue:
tmp = []
for i in range(len(queue)):
node = queue.popleft()
tmp.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(sum(tmp) / len(tmp))
return res
代码使用一个队列来存储节点,从根节点开始,每次将队列中的节点依次出队,并将它们的值加入到一个临时列表tmp
中。接着,将每个节点的左右子节点加入队列中。当队列中的节点全部遍历完成后,计算平均值并将其添加到结果列表res
中,最后返回res
即可。
代码的时间复杂度为O(n),其中n是二叉树的节点数。空间复杂度也为O(n),因为需要一个队列来存储节点。
本文正在参加「金石计划」