在问 · 算法题解

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

中等链表利用已建 next 指针力扣原题 ↗

题目描述

输入一棵完美二叉树:所有叶子位于同一层,并且每个非叶子节点都恰好有两个孩子。每个节点除了 val、left、right,还有一个 next 指针,初始时全部为空。

让每个节点的 next 指向同一层中紧挨在它右边的节点。若它已经是这一层最右边的节点,next 保持为空。返回修改后的根节点。

输出采用如下序列化方式:从每层最左节点出发,沿 next 依次写出节点值,每层结束后写一个 "#"。空树输出 []。

示例 1
输入:root = [1,2,3,4,5,6,7]
输出:[1,"#",2,3,"#",4,5,6,7,"#"]

解释:三层分别连成 1、2 -> 3、4 -> 5 -> 6 -> 7,每层末尾用 "#" 隔开。

示例 2
输入:root = []
输出:[]

解释:空树没有节点。

数据范围

  • 节点总数在 [0, 2^12 - 1] 之间。
  • -1000 <= node.val <= 1000

进阶:只用常数级别的额外空间。递归调用占用的栈空间不计入额外空间。

解题思路:利用已建 next 指针

把已经连好的一层当成链表来用。leftmost 指向每层最左节点;head 沿着这一层的 next 向右走,顺手给下一层连线:head.left.next = head.right(同一个父亲的两个孩子);如果 head 右边还有节点,head.right.next = head.next.left(跨父亲的两个相邻孩子)。这一层走完,下一层就全连好了,leftmost 下移一层继续。

为什么正确

处理 leftmost 所在层时,这一层的 next 已经全部连好,可以像链表一样从左到右遍历;下一层的 next 正在被逐对连好。

复杂度分析

时间 O(n):每个节点作为 head 访问一次;空间 O(1),只用 leftmost 和 head 两个指针,不需要队列。

易错点

跨父亲那一条线最容易漏:5 和 6 的父亲不同,必须靠上一层已经连好的 head.next 才能找到 6。另外要先判断 head.next 是否为空,最右边的父亲没有右邻居。循环条件写 leftmost.left 而不是 leftmost,否则会在叶子层访问 None.left。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def connect(self, root):
        leftmost = root
        while leftmost and leftmost.left:
            head = leftmost
            while head:
                head.left.next = head.right
                if head.next:
                    head.right.next = head.next.left
                head = head.next
            leftmost = leftmost.left
        return root

载入编辑器,自己跑一遍 →

其他解法

层序遍历通用但要 O(n) 队列;主解法把上一层已建好的 next 链当作队列用,额外空间 O(1)。

解法 2:层序遍历 时间 O(n),空间 O(n)

用队列做广度优先搜索,每轮先记下当前层的节点数。按从左到右的顺序取出本层节点,把上一个节点 prev 的 next 指向当前节点。同时把孩子加入队列,供下一轮使用。

不依赖完美二叉树的性质,对任意二叉树都适用。队列最多存放一层节点,最底层约有 n/2 个,不满足题目常数空间的进阶要求。

from collections import deque

class Solution:
    def connect(self, root):
        if not root:
            return root
        q = deque([root])
        while q:
            size = len(q)
            prev = None
            for _ in range(size):
                node = q.popleft()
                if prev:
                    prev.next = node
                prev = node
                if node.left:
                    q.append(node.left)
                if node.right:
                    q.append(node.right)
        return root

链表 专题的其他题目

查看 链表 全部题目 →