LeetCode 117:填充每个节点的下一个右侧节点指针 II
目录
LeetCode 117:填充每个节点的下一个右侧节点指针 II
题目描述
给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
【示例】
解题
对比LeetCode 116:填充每个节点的下一个右侧节点指针,二叉树不再是完美二叉树,但整体思路都是借助已经建立的同一层的连接关系,需要额外考虑当前节点右边的那个节点可能在更遥远的地方,而不是其父节点下一节点的右子节点。对于当前节点:
- 如果存在右子节点,则右子节点与其右边第一个出现的节点连接。
- 如果存在左子节点,则左子节点与其右边第一个出现的节点连接。
如何找到“右边第一个出现的节点”的位置呢?只要沿着其父节点一直向右寻找,直到找到第一个出现的子节点为止。这个过程也可以反过来,用递归的方式,即我们可以先找到最右边的节点,然后返回这个节点位置,直到找到其左边第一个节点,此时它是这个“左边第一个节点”的“右边第一个节点”。然后建立这两个节点的连接,这时候,当前位置的节点依然是它“左边第一个节点”的“右边第一个节点”。以此递归下去直到当前层完全建立连接。
当二叉树不再是完美二叉树时,会带来另外一个问题,那就是下一层的起点问题。下一层的起点应该是下一层出现的第一个节点位置。只需要将层间递归返回的最后一个节点位置作为起点即可。
以下是代码:
递归
/* // Definition for a Node. class Node { public: int val; Node* left; Node* right; Node* next; Node() : val(0), left(NULL), right(NULL), next(NULL) {} Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} Node(int _val, Node* _left, Node* _right, Node* _next) : val(_val), left(_left), right(_right), next(_next) {} }; */ class Solution { public: //用于层间递归的函数 Node *slice_connect(Node *node){ if (node==NULL) return NULL; //next记录最右边第一个节点 Node *next = slice_connect(node->next); //如果存在右子节点,则右子节点与其右边第一个出现的节点连接,并把右子节点作为右边第一个节点 if (node->right){ node->right->next = next; next = node->right; } //如果存在左子节点,则左子节点与其右边第一个出现的节点连接,并把左子节点作为右边第一个节点 if (node->left){ node->left->next = next; next = node->left; } return next; } Node* connect(Node* root) { if (root==NULL) return NULL; Node *cur_node = root; while(cur_node){ cur_node = slice_connect(cur_node); //将层间递归返回的最后一个节点位置作为下一层起点 } return root; } };
迭代
与递归方法相比,在同一层建立关系时只能从左到右,因此无法得到其右边第一个节点,但反过来,我们可以记录左边第一个节点。在层间遍历过程中:
- 如果当前节点存在左子节点,则下一层左边第一个节点(如果不为空的话)与其左子节点建立连接,并用其左子节点更新左边第一个节点。
- 如果当前节点存在右子节点,则下一层左边第一个节点(如果不为空的话)与其右子节点建立连接,并用其右子节点更新左边第一个节点。
还有一个需要注意的地方是,下一层起始位置。由于层间遍历时由左到右,所以需要额外引入变量来记录下一层起始位置。
以下是代码:
/* // Definition for a Node. class Node { public: int val; Node* left; Node* right; Node* next; Node() : val(0), left(NULL), right(NULL), next(NULL) {} Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} 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 NULL; Node *cur_node = root, *first_child = root->left ? root->left : root->right; //记录下一层第一个子节点位置 //外层由上到下 while (first_child){ Node *pre_node = NULL, *next_child = NULL; //内层由左到右 while (cur_node){ if (cur_node->left){ if (pre_node) pre_node->next = cur_node->left; pre_node = cur_node->left; //记录下下层第一个子节点位置,用于更新下一层第一个子节点位置 if (next_child == NULL) next_child = pre_node->left ? pre_node->left : pre_node->right; } if (cur_node->right){ if (pre_node) pre_node->next = cur_node->right; pre_node = cur_node->right; if (next_child == NULL) next_child = pre_node->left ? pre_node->left : pre_node->right; } cur_node = cur_node->next; } cur_node = first_child; first_child = next_child; } return root; } };
- 利用python 完成leetcode 117 填充每个节点的下一个右侧节点指针 II
- LeetCode 117. 填充每个节点的下一个右侧节点指针 II
- 【LeetCode-cpp】【49】117. 中等 填充每个节点的下一个右侧节点指针II Populating Next Right Pointers in Each Node II
- Leetcode 117. 填充每个节点的下一个右侧节点指针 II
- LeetCode 117. 填充每个节点的下一个右侧节点指针 II
- 117填充每个节点的下一个右侧节点指针 II
- LeetCode解题心得——填充每个节点的下一个右侧节点指针 II(python)
- LeetCode 117. 填充每个节点的下一个右侧节点指针 II
- LeetCode 117. 填充每个节点的下一个右侧节点指针 II(Java代码)
- LeetCode 116. 填充每个节点的下一个右侧节点指针(Java代码)
- LeetCode 116. 填充每个节点的下一个右侧节点指针
- LeetCode 116. 填充每个节点的下一个右侧节点指针
- 【LeetCode-cpp】【48】116. 中等 填充每个节点的下一个右侧节点指针 Populating Next Righ Pointers in Each Node
- Leetcode 116. 填充每个节点的下一个右侧节点指针
- 利用python 完成leetcode 116 填充每个节点的下一个右侧节点指针
- leetcode 填充每个节点的下一个右侧节点指针
- leetcode-116-填充每个节点的下一个右侧节点指针
- LeetCode解题心得——填充每个节点的下一个右侧节点指针(python)
- Leetcode 117 Populating Next Right Pointers in Each Node II 二叉树填充next指针指向右侧结点 II
- 填充每个节点的下一个右侧节点指针