二叉树_题目15:116. 填充每个节点的下一个右侧节点指针

75 阅读4分钟

题目15:116. 填充每个节点的下一个右侧节点指针

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…