给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {int val;Node *left;Node *right;Node *next;}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。
初始状态下,所有 next 指针都被设置为 NULL。
提示:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
解法一:迭代
迭代完成所有next的连接。从顶层开始,连接每一层每个节点的左右节点,并连接cur.right与cur.next.left。注意同层链表的尾边界。
class Solution:def connect(self, root: 'Node') -> 'Node':p = cur = rootwhile p and p.left:while cur:cur.left.next = cur.rightif cur.next:cur.right.next = cur.next.leftcur = cur.nextp = cur = p.leftreturn root
解法二:先序遍历
这个方法很神奇,按先序遍历的顺序,每个当前节点把它的左右孩子以及右孩子的右侧节点连接起来就可以了。
class Solution:def connect(self, root: 'Node') -> 'Node':if root and root.left:root.left.next = root.rightroot.right.next = root.next.left if root.next else Noneself.connect(root.left)self.connect(root.right)return root
解法三:后序遍历
比上面一个递归解法容易理解,不依赖先序遍历的特殊顺序,子问题是连接左右独立的子树。
子问题:将左子树的右边缘与右子树的左边缘逐层连接
退出条件:root为空,或root的左右子树为叶子节点
class Solution:def connect(self, root: 'Node') -> 'Node':if root and root.left:p = self.connect(root.left)q = self.connect(root.right)while p and q:p.next = qp, q = p.right, q.leftreturn root
解法四:先序遍历II
改写解法二,先连接左子树的右边缘和右子树的左边缘,然后再递归左右子树,可变成尾递归。
class Solution:def connect(self, root: 'Node') -> 'Node':def preorder(root):if root and root.left:p, q = root.left, root.rightwhile p and q:p.next = qp, q = p.right, q.leftself.connect(root.left)self.connect(root.right)preorder(root)return root
解法五:层次遍历
该方法不符合题目要求的空间复杂度。利用队列实现层次遍历(102. 二叉树的层序遍历)。
解法六:迭代II
依然是层次遍历。普通层次遍历需要从队列中取可用的节点,并将其左右孩子加入队列。而本题中当前层已经是一个链表,遍历链表是O(1)空间复杂度。因此利用当前层已经连接好的链表(这是控制空间复杂度的关键),使用尾插法逐一连接下层的节点。该解法同样适用于 117. 填充每个节点的下一个右侧节点指针 II。
同时该解法也是解法一的衍生。解法一并未保留上层信息,因此只能处理满二叉树的情况。
class Solution:def connect(self, root: 'Node') -> 'Node':head = root # head表示当前层的链表头while head: # 每次循环连接当前层的下一层dummy = tail = Node(0) # dummy.next为下一层的头部curr = headwhile curr: # 遍历当前层(已经连接),将下一层用尾插法连接if curr.left:tail.next = curr.lefttail = tail.nextif curr.right:tail.next = curr.righttail = tail.nextcurr = curr.nexthead = dummy.nextreturn root
