117.填充每个节点的下一个右侧节点指针Ⅱ python
填充每个节点的下一个右侧节点指针Ⅱ
- 题目
- 题目描述
- 示例 1:
- 示例 2:
- 提示:
- 题解
- 解决方案
- 方法:迭代法
- Python 实现
- 解释
- 提交结果
题目
题目描述
定一个二叉树:
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
进阶:
你只能使用常量级额外空间。
使用递归解题也符合要求,本题中递归程序的隐式栈空间不计入额外空间复杂度。
题解
对于这个问题,我们需要填充一个二叉树的每个 next
指针,使其指向同一层中的下一个右侧节点。如果当前节点是该层的最后一个节点,则将其 next
设置为 NULL
。与之前提到的完美二叉树不同,这里的二叉树可能不是完美的,即某些节点可能只有一个子节点或者没有子节点。
解决方案
我们可以使用一种迭代的方法来解决这个问题,利用已经建立的 next
指针遍历每一层。这种方法可以在常量级额外空间下完成任务(不包括输入和输出的空间)。
方法:迭代法
-
初始化:
- 如果根节点为空,直接返回。
- 使用一个指针
leftmost
来追踪当前层最左侧的节点。初始时指向根节点。
-
遍历每一层:
- 对于当前层,使用一个指针
head
遍历该层的所有节点。 - 当遍历当前层时,设置每个节点的左子节点和右子节点的
next
指针。- 如果存在左子节点,且当前节点的
next
不为空,则将左子节点的next
指向当前节点next
的左或右子节点(优先左子节点)。 - 类似的逻辑适用于右子节点。
- 如果存在左子节点,且当前节点的
- 在处理完当前层后,移动到下一层的最左侧节点,继续上述过程,直到所有层都被处理完毕。
- 对于当前层,使用一个指针
-
更新下一层的起始点:
- 在遍历当前层的同时,寻找下一层的最左侧非空节点。
Python 实现
def connect(root: 'Node') -> 'Node':
if not root:
return root
# Start with the root node
leftmost = root
while leftmost:
# Head will traverse the current level
head = leftmost
# Predecessor for the next level's nodes
prev = None
new_leftmost = None
# While we are at the current level
while head:
# Iterate over both children
for child in (head.left, head.right):
if child:
if prev:
prev.next = child
prev = child
# Set the new_leftmost to the first non-null child found
if not new_leftmost:
new_leftmost = child
# Move to the next node in the current level
head = head.next
# Move to the next level
leftmost = new_leftmost
return root
解释
- 初始化阶段:我们从根节点开始,
leftmost
指针用于跟踪每一层中最左边的节点。 - 遍历每一层:
- 使用
head
指针遍历当前层的所有节点。 - 对于每个节点的左右子节点,如果存在则进行连接,并更新
prev
指针指向当前子节点。 new_leftmost
用来记录下一层的第一个非空节点。
- 使用
- 更新下一层的起始点:在完成当前层的遍历后,将
leftmost
更新为new_leftmost
,以便进入下一层。
通过这种方式,我们避免了直接访问 None
的属性,并且保证了每次都能正确地找到下一层的起点,从而防止了潜在的 AttributeError
。这种方法依然保持了常量级的额外空间复杂度。