Skip to main content

116.填充每个节点的下一个右侧节点指针

标签: tree, depth-first-search, breadth-first-search

难度: Medium

通过率: 64.32%

原题链接: https://leetcode.com/problems/populating-next-right-pointers-in-each-node/description/

题目描述

给定一个完美二叉树,即所有叶子节点都在同一层,并且每个父节点都有两个孩子节点。定义二叉树节点如下:

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 = [] 输出: []

进阶:

  • 您只能使用常量级额外空间。
  • 递归方法也可以接受。假设隐式堆栈空间不算作额外空间。

解题思路

在一个完美二叉树中,每个父节点都有两个子节点,所有叶子节点都位于同一层。因此我们可以利用这种结构来填充 next 指针。

解决方案

使用层级遍历(类似广度优先搜索)的思路,但我们不使用显式队列,而使用 next 指针本身来遍历同一层中的节点。在每一层,我们将该层的每个节点的左、右子节点的 next 指针连接起来。

假设 current 是当前层的第一个节点,我们每次处理该层时,从 current 开始沿着 next 遍历。

  1. current 的左子节点的 next 指针指向 current 的右子节点。
  2. 如果 current 有下一节点 current.next,则将 current 右子节点的 next 指针指向 current.next 的左子节点。
  3. 当处理完当前层的所有节点后,进入下一层。
  4. 重复此过程直到所有节点的 next 指针都已设置。

由于这是一棵完美二叉树,我们可以通过访问每层的第一个节点来移动到下一层的第一个节点,即 current = current.left。这样我们利用了树本身的结构,因此不需要额外的存储空间。

代码实现

class Node:
def __init__(self, val=0, left=None, right=None, next=None):
self.val = val
self.left = left
self.right = right
self.next = next

class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root:
return None

# 从根节点开始,将每层的节点连接
leftmost = root

while leftmost.left:
# 遍历当前层的节点并连接下一层的节点
head = leftmost
while head:
# 将左子节点的 `next` 指向右子节点
head.left.next = head.right

# 如果 `head` 有下一个节点,则将当前右子节点的 `next` 指向下一个节点的左子节点
if head.next:
head.right.next = head.next.left

# 移动到同层的下一个节点
head = head.next

# 移动到下一层的左most节点
leftmost = leftmost.left

return root

复杂度分析

时间复杂度: O(n)O(n),其中 nn 是树中节点的数量。我们每个节点都只访问常数次,因此时间复杂度为 O(n)O(n) 空间复杂度: O(1)O(1),因为我们没有使用任何额外的存储空间(递归调用栈不算额外空间)。在每个节点的处理过程中,只使用有限的标志变量,因此空间复杂度为常数。