给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
public class Node {
public int val;
public Node left;
public Node right;
public Node next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL。
进阶:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
示例:
注:题目的描述来源于Leetcode
解法一:二叉树的遍历时讲过层序遍历,其实这个题目可以借鉴二叉树的层序遍历的思路来进行解决。其实从上面的示例中可以看出,就是进行二叉树的层序遍历,同时把遍历到的节点从左到右依次连接即可,此种解法比较简单,直接上代码
public Node connect(Node root) {
if (root == null) {
return null;
}
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
//获取这一层节点的数量
int size = queue.size();
for (int i = 0; i < size; ++i) {
Node node = queue.poll();
if (i < size - 1) {
//前size-1个节点逐次连接
node.next = queue.peek();
}
// 拓展下一层节点
if (node.left != null) {
queue.add(node.left);
}
if (node.right != null) {
queue.add(node.right);
}
}
}
return root;
}
此种解法的时间复杂度为O(N),空间复杂度为O(N)。
解法二:题目中限定了树是一颗完美二叉树,即每一层的节点都是满的,同时进阶中要求在O(1)的空间复杂度内解决,仔细分析树的连接方式,有两种连接方式。
第一种:如下图中的 4 和 5,节点具有相同的父节点 root,此种节点的连接方式比较简单,直接执行 root.left.next => root.right
第二种:如下图中的节点 5 和 节点 6,此种节点没有相同的父节点,但是从图中我们可以发现
(1)此次串联的两个节点恰好是上一层的 root.right节点 和n2.left节点
(2)由图克重root.next == n2
(3)经(1)和(2)分析,即转换为root.right.next => root.next.left,所以这里我们需要保证root.next不为空就可以
(4)经过前面三步的分析和下图表明,当我们要串联第 i 层节点时,需要先完成第 i-1 层的节点串联
(5)所以我们每一次找到每一层的最左侧节点(记住是一颗完美二叉树),依次执行连接即可。
(6)经过上面的分析,代码如下。
public Node connect1(Node root) {
if (root == null) {
return root;
}
//leftNodeForLevel表示每一层的最左侧节点,初始化为root
Node leftNodeForLevel = root;
//只需要leftNodeForLevel.left不等于空,表示还有下一层节点
while (leftNodeForLevel.left != null) {
//找到每一层的最左侧节点
Node head = leftNodeForLevel;
while (head != null) {
//有相同父节点的情况
head.left.next = head.right;
//没有相同父节点的情况
if (head.next != null) {
head.right.next = head.next.left;
}
//需要后移一个节点
head = head.next;
}
//继续处理下一层
leftNodeForLevel = leftNodeForLevel.left;
}
return root;
}
解法三:递归实现。其实就是把每一层相邻的节点串联起来,那如何定义递归函数?以及如何通过找到相邻的节点?
(1)可以定义一个递归函数connectTwoNode(Node node1,Node node2)表示串联起给定的两个节点,如下面的2 和 3。
(2)首先给定的两个节点肯定是要直接相连起来
(3)两个节点的left 节点和 right 节点肯定也要相连起来
(4)经过前面三步的分析,其实我们发现,只需要把node1 的 right 和 node2 的 left 节点相连起来就可以了。
(5)当然递归的终止条件是node1 为空 或者 node2 为空,经过上面的分析,即递归函数connectTwoNode的定义如下。
public Node connect2(Node root) {
if (root == null) return null;
//把root的left节点和right节点连接
connectTwoNode(root.left, root.right);
return root;
}
/**
* 定义:输入两个节点,将它俩连接起来
*
* @param node1
* @param node2
*/
public void connectTwoNode(Node node1, Node node2) {
if (node1 == null || node2 == null) {
return;
}
// 首先传入的两个节点肯定需要连接
node1.next = node2;
// 传入的两个节点的左右孩子也是得连接
connectTwoNode(node1.left, node1.right);
connectTwoNode(node2.left, node2.right);
// 传入的第一个节点的right节点和第二个节点的left节点也是得连接
connectTwoNode(node1.right, node2.left);
}