「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战」
填充每个节点的下一个右侧节点指针
完美二叉树情况
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
首先可以知道这是二叉树层序遍历的一道变形题,按照层序遍历的做法,我们将每一层的节点压入队列,依次处理每层节点,其次在层序遍历的做法下,我们得清楚这道变形的操作和限定条件,基于完美二叉树的特性,我们知道除了叶子节点外,每个节点都有其左右节点。我们把问题先限定到一两层中。
- 上一层操作下一层子节点的next指向
- 对于非叶子节点而言,它的左孩子节点的next指向它的右孩子节点,它的右孩子节点指向它的邻接节点(也就是同一层随它之后压入queue的节点)的左孩子 。前半部分好处理,但后半部分,我采用一个preNode记录这个未指向next指针的右孩子节点信息,因为此时邻接节点未弹出队列,获取不到邻接节点的左孩子信息 3.对于每一层的最后一个节点,我们直接将其next设置为null,并在下一层的开始,将preNode设置为null 代码如下:
var connect = function(root) {
if (!root) return root;
let queue = [];
queue.push(root);
while (queue.length) {
// 记录当前层级节点数
let length = queue.length;
// 存放每一层节点
let prenode = null;
for (let i = 0; i < length; i++) {
let node = queue.shift();
if(prenode !== null) {prenode.next = node.left;}
if (node.left !== null){
queue.push(node.left);
node.left.next = node.right;
}
if (node.right !== null) {
queue.push(node.right);
prenode = node.right
}
if (i === length - 1) {node.next = null;}
}
}
return root;
};
普通二叉树情况
给定一个二叉树
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
普通二叉树的下一个右侧节点做法也很简单,直接当层处理当层节点next指向,使用preNode(记录)指向这一层上一个节点,设置上一个节点的next,到这一层的最后一个节点时,直接将next设置为null,preNode设置为null。
好家伙,刚做完题来写博客,写到现在发现,可以直接把普通二叉树的代码用在完美二叉树上,因为完美二叉树就是普通二叉树的一种,这个思路也更清晰明了,没这么多条件限定(嘻嘻嘻,安慰一下不是自己犯蠢,是题目顺序问题)
代码如下:
var connect = function(root) {
if (!root) return root;
let queue = [];
queue.push(root);
while (queue.length) {
// 记录当前层级节点数
let length = queue.length;
// 存放每一层节点
let preNode = null;
for (let i = 0; i < length; i++) {
let node = queue.shift();
if (preNode) {
preNode.next = node
}
node.left&&queue.push(node.left);
node.right&&queue.push(node.right);
preNode = node;
if (i === length - 1) {
node.next = null;
}
}
}
return root;
};