当前位置: 首页 > news >正文

【LeetCode热题100道笔记】二叉树展开为链表

题目描述

给你二叉树的根结点 root ,请你将它展开为一个单链表:

展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
展开后的单链表应该与二叉树 先序遍历 顺序相同。

示例 1:
在这里插入图片描述
输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]

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

示例 3:
输入:root = [0]
输出:[0]

提示:
树中结点数在范围 [0, 2000] 内
-100 <= Node.val <= 100

进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

思考:前序遍历+左子树链表化

核心是递归处理左右子树:先将左、右子树分别展开为链表,再将左子树链表接到根节点的右指针,最后将原右子树链表接到左子树链表的尾部,实现“根→左子树链表→右子树链表”的前序顺序。

算法过程

  1. 递归终止条件:若当前节点为null(空树/叶子节点的子树),返回null(无需处理)。
  2. 递归展开子树
    • 递归展开左子树,得到左子树链表的头节点left
    • 递归展开右子树,得到右子树链表的头节点right
  3. 重组当前节点的指针
    • 将当前节点的右指针指向左子树链表(root.right = left),左指针置为nullroot.left = null);
    • 遍历左子树链表至尾部(找到最后一个节点),将其右指针指向右子树链表(current.right = right)。
  4. 返回当前节点:作为上层节点的左/右子树链表头,完成递归回溯。

时空复杂度

  • 时间复杂度:O(n),n为二叉树节点总数。
    原因:每个节点仅被访问1次(递归处理),遍历左子树链表尾部的操作总次数为O(n)(每个节点最多被遍历1次),总时间与节点数线性相关。
  • 空间复杂度:O(h),h为二叉树高度。
    原因:递归调用栈深度取决于树高,平衡树h=O(log n),链状树h=O(n);额外空间仅为递归栈,无其他存储开销。

代码(前序遍历版)

/*** Definition for a binary tree node.* function TreeNode(val, left, right) {*     this.val = (val===undefined ? 0 : val)*     this.left = (left===undefined ? null : left)*     this.right = (right===undefined ? null : right)* }*/
/*** @param {TreeNode} root* @return {void} Do not return anything, modify root in-place instead.*/
var flatten = function(root) {preOrder(root);
};// 辅助函数:将以root为根的树展开为链表,返回展开后的头节点
function preOrder(root) {if (!root) return null; // 空节点直接返回// 递归展开左、右子树let left = preOrder(root.left);let right = preOrder(root.right);// 1. 将左子树链表接到根节点的右指针,左指针置空root.right = left;root.left = null;// 2. 找到左子树链表的尾部,将右子树链表接在其后let current = root;while (current.right) { // 遍历至左子树链表的最后一个节点current = current.right;}current.right = right;return root; // 返回当前节点作为上层的子树链表头
}

关键逻辑解析

  1. 为何用前序遍历?
    题目要求展开后的链表顺序与前序遍历一致(根→左→右),前序遍历的递归顺序天然匹配这一需求:先处理根节点,再处理左子树,最后处理右子树,确保重组后的指针顺序正确。

  2. 左指针为何必须置空?
    展开后的链表要求所有节点的左指针为null,仅保留右指针指向后续节点。若不置空左指针,会导致链表中残留左子树引用,破坏“链表”的结构定义。

  3. 如何高效找到左子树链表的尾部?
    代码中通过while (current.right)循环遍历左子树链表至尾部,这是最直观的实现。对于极端情况(左子树为链状),该操作时间复杂度为O(k)(k为左子树节点数),但整棵树的总遍历次数仍为O(n)(每个节点最多被遍历1次),不影响整体时间复杂度。

  4. 是否可以优化空间复杂度?
    上述递归实现的空间复杂度为O(h),若需进一步优化至O(1),可采用Morris遍历(线索化遍历),通过修改空指针临时指向前驱/后继节点,避免递归栈开销,但代码逻辑会更复杂。

示例解析(以 root = [1,2,5,3,4,null,6] 为例)

  1. 递归展开左子树(2→3→4)和右子树(5→6);
  2. 根节点1的右指针指向左子树2,左指针置空;
  3. 遍历左子树链表至尾部(4),将其右指针指向右子树5;
  4. 最终链表为:1→2→3→4→5→6,符合前序遍历顺序。

该过程通过递归自然实现了“根→左→右”的顺序重组,确保链表结构正确且原地修改(不创建新节点)。


文章转载自:

http://Re0n8x3d.pkfpL.cn
http://uP4g579t.pkfpL.cn
http://iHn5E7Od.pkfpL.cn
http://rJHGBxkU.pkfpL.cn
http://w24I7hnx.pkfpL.cn
http://NrtpzSYu.pkfpL.cn
http://Uli7jsxJ.pkfpL.cn
http://Odqnt9Kd.pkfpL.cn
http://SVkvG5Qf.pkfpL.cn
http://VksJoeHU.pkfpL.cn
http://KaSQEMuS.pkfpL.cn
http://AtSg79Bx.pkfpL.cn
http://gUUwg3xI.pkfpL.cn
http://yxZX0g2K.pkfpL.cn
http://w9ofUeJG.pkfpL.cn
http://viNocB39.pkfpL.cn
http://ilqvS9bT.pkfpL.cn
http://bvDUgM3v.pkfpL.cn
http://5j8b0R8v.pkfpL.cn
http://BekG54kV.pkfpL.cn
http://EbvQWqBJ.pkfpL.cn
http://e5JngIDA.pkfpL.cn
http://scFJc3vV.pkfpL.cn
http://twKAHhA5.pkfpL.cn
http://cX3voBak.pkfpL.cn
http://dvLzJysL.pkfpL.cn
http://20KTFXTr.pkfpL.cn
http://cRPK4sTn.pkfpL.cn
http://XxN8P94G.pkfpL.cn
http://DwPUvPcK.pkfpL.cn
http://www.dtcms.com/a/369907.html

相关文章:

  • 【LeetCode热题100道笔记】对称二叉树
  • MySQL与ES索引区别
  • 捷多邦揭秘超厚铜板:从制造工艺到设计关键环节​
  • Nestjs框架: 基于权限的精细化权限控制方案与 CASL 在 Node.js 中的应用实践
  • Zynq设备与电脑相连方式
  • 《UE5_C++多人TPS完整教程》学习笔记48 ——《P49 瞄准偏移(Aim Offset)》
  • 【数据结构】带哨兵位双向循环链表
  • Python基础之封装单继承
  • [数据结构] ArrayList(顺序表)与LinkedList(链表)
  • Fantasia3D:高质量文本到3D内容创建工具
  • Elasticsearch面试精讲 Day 10:搜索建议与自动补全
  • 【3D算法技术】blender中,在曲面上如何进行贴图?
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘mkdocs’问题
  • 【牛客刷题-剑指Offer】BM18 二维数组中的查找:一题四解,从暴力到最优
  • 推荐的Java服务环境:JDK17+ZGC(JDK 21的ZGC支持分代回收,性能更高)
  • [光学原理与应用-431]:非线性光学 - 能生成或改变激光波长的物质或元件有哪些?
  • 心路历程- Linux用户组的整理
  • 前端登录鉴权详解
  • CodeSandbox Desktop:零配置项目启动工具,实现项目环境隔离与Github无缝同步
  • Lua > Mac Mini M4安装openresty
  • SpringBootWeb 篇-深入了解 ThreadLocal 存在内存泄漏问题
  • Django 项目6:表单与认证系统
  • 【架构艺术】通过标准化事件解决变更检测能力的调度问题
  • Eureka与Nacos的区别-服务注册+配置管理
  • Python毕业设计推荐:基于Django的饮食计划推荐与交流分享平台 饮食健康系统 健康食谱计划系统
  • 基于 Gemini 的 CI/CD 自动化测评 API 集成实战教程
  • 基于定制开发开源AI智能名片S2B2C商城小程序的DMP平台离线文件上传功能优化研究
  • 友猫社区APP源码与小程序端部署详解
  • HJ65查找两个字符串a,b中的最长公共子串(medium,dp,进入题目后题目序号是HJ21)
  • 如何减少微型导轨表面破损情况?