「前端刷题」116. 填充每个节点的下一个右侧节点指针

87 阅读1分钟

「这是我参与2022首次更文挑战的第24天,活动详情查看:2022首次更文挑战」。

题目

链接:leetcode-cn.com/problems/po…

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

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指针不断连接

var connect = function(root) {
    if(root === null) return root
    const stack = [root]
    //每次出栈一层入栈一层,直至全部出栈完成全部遍历链接
    while(stack.length){
        //存一下现有栈的长度,即为本层的元素个数
        const count = stack.length
        for(let i = 0; i < count; i++){
            //提取出栈的第一个元素并删除
            element = stack.shift()
            //提取出的元素与现在栈的第一个元素相连,即为同层链接
            if(i < count -1) element.next = stack[0]
            //将下一层的元素放入栈中
            if(element.left != null) stack.push(element.left)
            if(element.right != null) stack.push(element.right)
        }
    }
    return root
};

指针分类

var connect = function(root) {
    if(root === null) return root
    //设定每层最左侧的元素lvLeft
    let lvLeft = root
    //保证lvLeft.left不为null,逐层遍历两种next指针
    while(lvLeft.left){
        //为了保证外循环参数lvLeft不受影响,设定内循环参数loopLeft
        let loopLeft = lvLeft
        while(loopLeft){
            //第一种next指针,拥有同个父节点
            loopLeft.left.next = loopLeft.right
            //第二种next指针,从父节点的right指向父节点next的left
            if(loopLeft.next){
                loopLeft.right.next = loopLeft.next.left
            }
            //父节点推进
            loopLeft = loopLeft.next
        }
        //每次向下一层
        lvLeft = lvLeft.left
    }
    return root
};

dfs递归

学习了一下大佬的做法,不断深入最中间的连接,也就是指针分类方法中的第二种指针
在每次dfs中,连接两个父节点后,向下推进,连接左节点的右孩子和右节点的左孩子
直至二叉树的尽头,然后开始dfs左节点的左孩子,和右节点的右孩子

var connect = function(root) {
    dfs(root)
    return root
}

const dfs = (root) => {
	if(root === null)  return
	let left = root.left
	let right = root.right
	while(left) {
		left.next = right
		left = left.right
		right = right.left
	}
	dfs(root.left)
	dfs(root.right)
}