题目15:116. 填充每个节点的下一个右侧节点指针
同类题目
前置知识
- 无
题目描述
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
示例 1:
输入:root = [1,2,3,4,5,6,7]
输出:[1,#,2,3,#,4,5,6,7,#]
解释:给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,'#' 标志着每一层的结束。
示例 2:
输入:root = []
输出:[]
提示:
- 树中节点的数量在
[0, 212 - 1]范围内 -1000 <= node.val <= 1000
进阶:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
思路分析
方法一:递归+前序
对于树中的每一个节点要做的事情
- 该节点的左孩子的
next指向右孩子root->left->next = root->right - 该节点的右孩子的
next指向空root->right->next = nullptr或者指向该节点的next的左孩子root->right->next = root->next->left
注意:树中的每一个节点的 next 默认情况下指向nullptr。
针对该节点的右孩子的next 的修改的前提条件是该节点的next已经设置过,因此要在前序位置做。
程序代码
方法一:
// https://leetcode.cn/problems/populating-next-right-pointers-in-each-node/
// 116. 填充每个节点的下一个右侧节点指针
class Solution {
public:
void travel(Node* root)
{
if(root->left == nullptr || root->right == nullptr)
{
return;
}
// 前序位置
root->left->next = root->right;
if(root->next)
{
root->right->next = root->next->left;
}
// 右孩子的修改,需要自己的next 存在
travel(root->left);
travel(root->right);
}
Node* connect(Node* root) {
if(root == nullptr)
{
return root;
}
travel(root);
return root;
}
};
复杂度分析
时间复杂度:O(N),其中 N 是二叉树中的节点个数。每个节点都会遍历一次。
空间复杂度:O(logN) ,其中logN 为二叉树的高度。由于本题是完美二叉树(满二叉树),所以高度为O(logN)。
思路分析
方法二:层序遍历+辅助队列
定义一个辅助队列,遍历时将队列中的所有元素取出,这样能保证每次从队列中拿出来遍历的元素都是属于同一层的,遍历的过程中修改每个节点的 next 指针,同时将左右孩子压入队列。
注意:树中的每一个节点的 next 默认情况下指向nullptr。
程序代码
方法二:
class Solution {
public:
void travel(Node* root)
{
if(root == NULL)
{
return;
}
queue<Node*> que;
que.push(root);
while(!que.empty())
{
// 当前层的节点个数
int size = que.size();
for(int i=0;i<size;i++)
{
// 当前层的第一个节点
Node *node = que.front();
que.pop();
if(i < size - 1)
{
node->next = que.front();
}
if(node->left)
{
que.push(node->left);
}
if(node->right)
{
que.push(node->right);
}
}
}
}
Node* connect(Node* root) {
travel(root);
return root;
}
};
复杂度分析
时间复杂度:O(N),其中 N是二叉树中的节点个数。每个节点都会遍历一次。
空间复杂度:O(N) ,其中N 为层次的最大节点个数。由于本题是完美二叉树(满二叉树),所以最后一层的个数为最大值N/2。
代码思路
层序遍历+链表
对于每一层中的节点
- 找到这一层的最左节点,作为链表的
head - 该节点的左孩子的
next指向右孩子root->left->next = root->right - 该节点的右孩子的
next指向空root->right->next = nullptr或者指向该节点的next的左孩子root->right->next = root->next->left
注意:树中的每一个节点的 next 默认情况下指向nullptr。
程序代码
class Solution {
public:
Node* connect(Node* root) {
if (root == nullptr) {
return root;
}
// 从根节点开始
Node* leftmost = root;
while (leftmost->left != nullptr) {
// 遍历这一层节点组织成的链表,为下一层的节点更新 next 指针
Node* head = leftmost;
while (head != nullptr) {
// 同一个父节点
head->left->next = head->right;
// 不是同一个父节点
if (head->next != nullptr) {
head->right->next = head->next->left;
}
// 指针向后移动
head = head->next;
}
// 去下一层的最左的节点
leftmost = leftmost->left;
}
return root;
}
};
复杂度分析
时间复杂度:O(n),其中 n 是二叉树中的节点个数。每个节点都会遍历一次。
空间复杂度:O(1)。
题目感悟
更多相关知识:github.com/pingguo1987…