1.题目描述
给定一个二叉树:
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
进阶:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序的隐式栈空间不计入额外空间复杂度。
2.解题思路
2.1 层序遍历-BFS
借助队列进行层序遍历,在遍历的过程中,给当前层的元素next域赋值,同时如果当前遍历元素有left/right孩子时,再将下层结点入队,当队中元素为空时,就完成了所有next域的赋值。
2.2 递归解法-DFS
定义一个函数getNext(Node node)用于寻找下一个结点;
在遍历root的过程中,我们要处理root的左右孩子的next域,存在以下几种情况:
- root的左右孩子都不为空,那么root.left.next = root.right
- root的左孩子不为空但右孩子为空,那么root.left.next = getNext(root.next),因为右孩子为空,所以要到当前root的兄弟/堂兄弟结点中去找左孩子的next
- root的右孩子不为空时,需要找右孩子的next,同上,它的root.right.next = getNext(root.next)
- 当处理完root的左右孩子的next域后,需要递归的寻找右子树和左子树
注:递归时,一定要先处理右子树,再处理左子树,因为如果先处理左子树会有节点的next域明明有下一个结点,但却被置为null,这样就会使的连接的过程中丢失结点,如果先处理右子树,在getNext(root.next)时,当前的root.next一定是已经指向了堂兄弟的,所以getNext能找到正确的结果
3.代码实现
3.1 思路1
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if (root == null) return root;
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int sz = queue.size();
for (int i = 0; i < sz; i++) {
Node cur = queue.poll();
if (i == sz - 1) {
cur.next = null;
} else {
cur.next = queue.peek();
}
if (cur.left != null) {
queue.offer(cur.left);
}
if (cur.right != null) {
queue.offer(cur.right);
}
}
}
return root;
}
}
3.2 思路2
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if (root == null) {
return root;
}
//如果当前结点左右孩子都不为空,那么左孩子的next就是右孩子
if (root.left != null && root.right != null) {
root.left.next = root.right;
}
//如果左不空,右空,左孩子的next就通过getNext(root.next)找root的兄弟结点的孩子
if (root.left != null && root.right == null) {
root.left.next = getNext(root.next);
}
//如果右不空,还要给右孩子找next域
if (root.right != null) {
root.right.next = getNext(root.next);
}
//当前结点的左右孩子都处理完毕,需要递归的处理以左右孩子为根的子树
connect(root.right);
connect(root.left);
return root;
}
public Node getNext(Node node) {
if (node == null) {
return null;
}
if (node.left != null) {
return node.left;
}
if (node.right != null) {
return node.right;
}
if (node.next != null) {
return getNext(node.next);
}
return null;
}
}