题目链接:117. 填充每个节点的下一个右侧节点指针 II

题目描述

给定一个二叉树,填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL。初始状态下,所有 next 指针都被设置为 NULL

示例

输入:root = [1,2,3,4,5,null,7]
输出:[1,#,2,3,#,4,5,7,#]
解释:按层序遍历,'#' 表示每一层的末尾。

思路

层次遍历

这道题的核心是按层次遍历二叉树,并将每一层的节点通过 next 指针连接起来。由于树的结构不一定是完美二叉树,每个节点的左右子树数量可能不同,导致每层节点数量不均匀。因此,我们不能简单地直接使用完全二叉树的解法,而是需要根据当前节点的左右子节点来动态连接它们。

解题过程

方法运用

我们需要逐层遍历二叉树并构建 next 指针。在遍历时,使用以下几点策略:

  1. 从左到右遍历当前层节点

    • 对于每个节点,我们检查它是否有左子节点和右子节点。如果存在子节点,依次连接它们。
  2. 使用 next 指针帮助跨节点连接

    • 在跨越同一层不同父节点时(即当前节点的右子节点和下一个节点的左子节点),可以利用上一层已经构建好的 next 指针,来顺利访问该层的其他节点。
  3. 构建下一层的连接关系

    • 遍历当前层时,将下一层的节点依次连接起来,并通过虚拟节点 dummy 来指向下一层的第一个节点。
  4. 遍历完一层后进入下一层

    • 处理完当前层后,我们通过 dummy.next 找到下一层的第一个节点,然后继续处理这一层,直到所有层遍历完毕。

代码实现

下面是该算法的完整 Java 实现:

class Solution {
public Node connect(Node root) {
if (root == null) {
return null;
} // 从当前层的头开始
Node currentLevel = root; while (currentLevel != null) {
Node dummy = new Node(0); // 虚拟头节点,方便处理下一层的连接
Node prev = dummy; // 用来连接下一层节点的指针
Node curr = currentLevel; // 当前层的节点 while (curr != null) {
if (curr.left != null) {
prev.next = curr.left;
prev = prev.next;
}
if (curr.right != null) {
prev.next = curr.right;
prev = prev.next;
}
curr = curr.next; // 移动到当前层的下一个节点
} currentLevel = dummy.next; // 进入下一层
} return root;
}
}

代码细节

  1. Node

    • Node 类代表二叉树的节点,每个节点包含 val(节点值),left(左子节点),right(右子节点)和 next(右侧节点的指针)。
  2. 主逻辑

    • currentLevel 变量用于追踪每一层的开始节点。
    • 通过 dummy 虚拟节点和 prev 指针将下一层的节点按顺序连接起来。
    • 遍历完当前层后,dummy.next 就会指向下一层的第一个节点,赋值给 currentLevel 以开始处理下一层。
  3. 循环控制

    • 内层 while (curr != null) 循环用于遍历当前层的所有节点,并连接它们的子节点。
    • 外层 while (currentLevel != null) 循环用于逐层处理,直到所有节点都完成连接。

常见问题解答

1. 为什么 currentLevel = dummy.next 能进入下一层?

dummy 是一个虚拟头节点,它用于帮助我们方便地连接当前层的子节点,即下一层的所有节点。当遍历当前层时,每次找到一个子节点,就把它连接到 dummy 的链表中(由 prev.next 来完成)。因此,dummy.next 最终会指向下一层的第一个节点。通过 currentLevel = dummy.next,我们就能顺利进入下一层的第一个节点,开始处理下一层。

2. 为什么需要 dummy 节点?

dummy 节点的作用是简化逻辑。在处理下一层节点时,我们需要将它们串起来,并且要记录下一层的第一个节点。使用 dummy 节点可以方便地处理这种情况,它始终指向下一层的开始位置,无需特殊处理第一个节点与其他节点的连接,简化了代码。

3. 该算法的时间和空间复杂度如何?

  • 时间复杂度:O(n),因为每个节点只会被访问一次。
  • 空间复杂度:O(1),除了递归栈之外,使用的额外空间是常数级别的。

今日算法随笔:填充每个节点的下一个右侧节点指针 II的更多相关文章

  1. [leetcode-117]填充每个节点的下一个右侧节点指针 II

    (1 AC) 填充每个节点的下一个右侧节点指针 I是完美二叉树.这个是任意二叉树 给定一个二叉树 struct Node { int val; Node *left; Node *right; Nod ...

  2. [LeetCode] 116. 填充每个节点的下一个右侧节点指针

    题目链接 : https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/ 题目描述: 给定一个完美二叉树 ...

  3. Java实现 LeetCode 117 填充每个节点的下一个右侧节点指针 II(二)

    117. 填充每个节点的下一个右侧节点指针 II 给定一个二叉树 struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每 ...

  4. Java实现 LeetCode 116 填充每个节点的下一个右侧节点指针

    116. 填充每个节点的下一个右侧节点指针 给定一个完美二叉树,其所有叶子节点都在同一层,每个父节点都有两个子节点.二叉树定义如下: struct Node { int val; Node *left ...

  5. LeetCode OJ:Populating Next Right Pointers in Each Node II(指出每一个节点的下一个右侧节点II)

    Follow up for problem "Populating Next Right Pointers in Each Node". What if the given tre ...

  6. 117. 填充每个节点的下一个右侧节点指针 II

    Q: 给定一个二叉树 struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每个 next 指针,让这个指针指向其下一个右 ...

  7. leetcode117. 填充每个节点的下一个右侧节点指针 II

    给定一个二叉树struct Node {  int val;  Node *left;  Node *right;  Node *next;}填充它的每个 next 指针,让这个指针指向其下一个右侧节 ...

  8. leetcode 117. 填充每个节点的下一个右侧节点指针 II(二叉树,DFS)

    题目链接 https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/ 题目大意 给定一个二叉树 s ...

  9. 【LeetCode】116. 填充每个节点的下一个右侧节点指针 Populating Next Right Pointers in Each Node 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 递归 日期 题目地址:https://leetcode ...

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

    time O(n) ,sapce O(n) /* // Definition for a Node. class Node { public: int val; Node* left; Node* r ...

随机推荐

  1. SpringBoot2.X新版本配置拦截器在项目中的使用

    拦截器:和过滤器用途基本类似 SpringBoot2.X新版本配置拦截器 implements WebMvcConfigure 自定义拦截器 HandlerInterceptor preHandle: ...

  2. 全网最适合入门的面向对象编程教程:08 类和对象的Python实现-@property装饰器:把方法包装成属性

    全网最适合入门的面向对象编程教程:08 类和对象的 Python 实现-@property 装饰器:把方法包装成属性 摘要: 本文主要对@property 装饰器的基本定义.使用场景和使用方法进行了介 ...

  3. workman和swoole区别和异同

    swoole是使用C语言实现的socket通信框架,workerman则是使用纯php实现的socket框架,二者进程模型上也存在很多的不同. 先说下swoole的进程模型,看一下以下解析图 mast ...

  4. django 信号 新增和删除信的合用

    from django.db.models.signals import post_save, post_delete from django.dispatch import receiver fro ...

  5. [oeasy]python0111_字型码_字符字型编码_点阵字库_ascii演化

    编码进化 回忆上次内容 上次回顾了 早期的英文字符点阵 最小的 3*5 通用的 5*7   点阵字库逐渐规范化 ​     添加图片注释,不超过 140 字(可选)     这些点阵字符的字型 究竟是 ...

  6. ComfyUI进阶:Comfyroll插件 (五)

    ComfyUI进阶:Comfyroll插件 (五) 前言: 学习ComfyUI是一场持久战,而Comfyroll 是一款功能强大的自定义节点集合,专为 ComfyUI 用户打造,旨在提供更加丰富和专业 ...

  7. ABC349

    A link 其实,有人赢比赛,就有人输比赛,一加一减,不管进行多少场比赛,最后所有人的分数和一定是\(0\). 那么知道\(n-1\)个人的分数和,就可以知道第\(n\)个人的了. 点击查看代码 # ...

  8. 记一次在openEuler系统下离线编译升级到openssh9.8p1

    缘起 由于某个项目上甲方对服务器进行漏洞扫描,系统为:openEuler 22.03 (LTS-SP4).提示现有OpenSSH版本存在漏洞,需要升级到openssh-9.8p1的版本(目前最新),遂 ...

  9. 简单聊聊WebDAV

    1.什么是WebDAV? WebDAV是一种基于HTTP协议的扩展,旨在提供在Web服务器上进行文件管理的标准化解决方案.它允许用户通过网络对远程主机上的文件进行读写.编辑和删除操作.与传统的HTTP ...

  10. hbuilderx打正式包所需的私钥证书的创建方法

    现在使用uniapp作为底层框架来开发app应用已经成为了很多公司的事实标准,而uniapp的开发工具hbuilderx云打包的时候,需要私钥证书和证书profile文件. 而且还需要将打包好的ipa ...