题目:117.填充每个节点的下一个右侧节点指针 II
给定一个二叉树:
class 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
指针,使它指向其右侧节点,可以通过层序遍历来实现。具体的做法是利用广度优先搜索(BFS),逐层遍历树中的节点,并将当前节点的 next
指针指向同一层的下一个节点。如果没有下一个节点,就将 next
指针指向 null
。
- 使用
Queue
来存储每层的节点。 - 对每层的节点,除了最后一个节点,其
next
指针应该指向同层的下一个节点。 - 最后一个节点的
next
指针应该指向null
。
- 时间复杂度:O(n)
- 空间复杂度:O(n)
代码
public Node connect(Node root) {
if (root == null) {
return null;
}
// 使用队列进行层序遍历
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
// 当前层的节点数
int size = queue.size();
Node prev = null;
for (int i = 0; i < size; i++) {
Node current = queue.poll();
// 将前一个节点的 next 指向当前节点
if (prev != null) {
prev.next = current;
}
prev = current;
// 将当前节点的子节点加入队列
if (current.left != null) {
queue.offer(current.left);
}
if (current.right != null) {
queue.offer(current.right);
}
}
// 当前层最后一个节点的 next 指针指向 null
prev.next = null;
}
return root;
}
思路2
要在常量级别的额外空间内填充二叉树每个节点的 next
指针,使其指向下一个右侧节点,如果没有右侧节点则指向 null
。这个问题要求我们不能使用额外的数据结构如队列或栈,因此需要利用树的结构进行原地修改。
使用当前层的
next
指针:- 我们可以通过已建立的
next
指针,从左到右遍历每一层。在遍历当前层时,将下一层的节点连接起来。 - 从树的根节点开始处理,依次处理每一层的节点,将
next
指针正确连接到下一个节点。
- 我们可以通过已建立的
层级遍历:
- 在每一层的遍历中,通过
next
指针遍历该层的所有节点,并连接其左右子节点。 - 使用两个指针:
current
用于遍历当前层,nextLevel
用于记录下一层的起始节点。
- 在每一层的遍历中,通过
- 时间复杂度:O(n)
- 空间复杂度:O(1)
代码
public Node connect(Node root) {
Node dummy = new Node();
Node current = root;
// 遍历每一层
while (current != null) {
dummy.next = null;
// 下一层的链表
Node nextLevel = dummy;
// 遍历当前层的链表
while (current != null) {
if (current.left != null) {
// 下一层的相邻节点连起来
nextLevel.next = current.left;
nextLevel = nextLevel.next;
}
if (current.right != null) {
// 下一层的相邻节点连起来
nextLevel.next = current.right;
nextLevel = nextLevel.next;
}
// 当前层链表的下一个节点
current = current.next;
}
// 下一层链表的头节点
current = dummy.next;
}
return root;
}