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

Leetcode 深度优先搜索 (12)

114. 二叉树展开为链表

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

示例 1:
在这里插入图片描述

输入: root = [1,2,5,3,4,null,6]
输出: [1,null,2,null,3,null,4,null,5,null,6]

思路一:递归拼接(先展平左右,再重接)

  • 递归出口:root 为空直接返回。
  • 先递归展平 root.left 与 root.right,使两侧均变成右指针链。
  • 若左链存在:
  • 记录 leftList = root.left、rightList = root.right。
  • 沿 right 指针找到 leftList 的尾结点 tail。
  • 将 root.right 指向 leftList,并将 root.left 置为 null。
  • 将 tail.right 接到原来的 rightList。

复杂度: 时间 O(n^2) 最坏(退化链时 tail 查找),空间 O(h)(递归栈)。

class Solution {/*** Recursively flattens the binary tree rooted at root into a right-skewed linked list* in preorder order, in-place.*/public void flatten(TreeNode root) {if (root == null) return;// 1) Flatten left and right subtreesflatten(root.left);flatten(root.right);// 2) If a left flattened list exists, splice it between root and original right listif (root.left != null) {TreeNode leftList = root.left;TreeNode rightList = root.right; // might be null// Find tail of left list (rightmost node after flatten)TreeNode tail = leftList;while (tail.right != null) {tail = tail.right;}// Move left list to right, nullify leftroot.right = leftList;root.left = null;// Append original right listtail.right = rightList;}}
}

思路二:递归返回尾结点(避免找尾的 O(n^2))

  • 定义辅助函数 flattenAndReturnTail(root):将以 root 为根的子树原地展平,并返回展平后链表的尾结点。
  • 递归处理左右子树,得到 leftTail 与 rightTail。
  • 若存在左链:
    • 将 leftTail.right 指向原 root.right;
    • 将 root.right 指向 root.left,并将 root.left 置空;

返回尾结点:优先 rightTail,其次 leftTail,否则为 root 自身。
复杂度:时间 O(n),空间 O(h)(递归栈)。

class Solution {/*** Recursively flattens the binary tree rooted at root into a right-skewed linked list* in preorder order, in-place. Wrapper that uses a helper returning the tail node.*/public void flatten(TreeNode root) {flattenAndReturnTail(root);}// Returns the tail node of the flattened list rooted at 'root'private TreeNode flattenAndReturnTail(TreeNode root) {if (root == null) return null;// Flatten left and right subtrees and get their tailsTreeNode leftTail = flattenAndReturnTail(root.left);TreeNode rightTail = flattenAndReturnTail(root.right);// If there is a left flattened list, splice it between root and original right listif (leftTail != null) {// Attach original right to the end of left listleftTail.right = root.right;// Move left list to right and nullify leftroot.right = root.left;root.left = null;}// Return the tail of the fully flattened listif (rightTail != null) return rightTail;if (leftTail != null) return leftTail;return root;}
}

思路三:逆先序(right-left-root)+ 全局 prev 指针

  • 维护一个全局/成员变量 prev,表示“已经展平成链表的头结点”(在逆先序构造的当前阶段)。
  • 按顺序递归访问 right → left → root:
  • 回到 root 时,将 root.right 指向 prev,root.left 置为 null;
  • 更新 prev = root。
  • 因为先处理 right,再处理 left,能保证最终链表顺序是先序(root-left-right);整个过程只遍历每个结点一次,时间 O(n),递归栈空间 O(h)。
class Solution {// prev 指向“已经展平成链表的当前头结点”private TreeNode prev = null;/*** 使用逆先序(right -> left -> root)和全局 prev 指针,就地展平为先序右链。*/public void flatten(TreeNode root) {prev = null; // 每次调用前重置reversePreorder(root);}private void reversePreorder(TreeNode node) {if (node == null) return;// 先处理右子树、再处理左子树reversePreorder(node.right);reversePreorder(node.left);// 回溯到当前节点时,接到 prev 前面,并断开左指针node.right = prev;node.left = null;prev = node;}
}

思路四:迭代栈模拟先序

  • 用栈按先序遍历(root-left-right)。
  • 维护一个指针 prev 指向“已连接链表的最后一个节点”。
  • 每弹出当前节点 cur:
  • 若 prev 不为 null,则令 prev.right = cur 且 prev.left = null,把 cur 接到链表末尾。
  • 为保证先序顺序,先把 cur.right 压栈,再把 cur.left 压栈(这样左子树先被处理)。
  • 更新 prev = cur。
  • 遍历结束后,确保最后一个节点的 left 为 null。
class Solution {/*** Iterative preorder (root-left-right) using a stack.* Links nodes into a right-only list as we traverse; nullifies all left pointers.* Time: O(n), Space: O(n) in worst case (stack).*/public void flatten(TreeNode root) {if (root == null) return;Deque<TreeNode> stack = new ArrayDeque<>();stack.push(root);TreeNode prev = null;while (!stack.isEmpty()) {TreeNode cur = stack.pop();if (prev != null) {prev.right = cur;prev.left = null;}// Push right first so that left is processed first (preorder)if (cur.right != null) stack.push(cur.right);if (cur.left != null) stack.push(cur.left);prev = cur;}// Ensure the last node's left is nullif (prev != null) prev.left = null;}
}
http://www.dtcms.com/a/343514.html

相关文章:

  • 20250821 圆方树总结
  • 通信基础理论
  • C语言基础习题——01
  • plantsimulation小知识25.08.21 对话框的使用方法
  • 深圳大学-计算机信息管理课程实验 C++ 自考模拟题
  • 【LeetCode】18. 四数之和
  • C语言:字符函数与字符串函数(2)
  • ORA-16331: container is not open ORA-06512: at “SYS.DBMS_LOGMNR“
  • Hexo 博客图片托管:告别本地存储,用 PicGo + GitHub 打造高速稳定图床
  • ArcMap 数据框裁剪(Data Frame Clip)操作教程
  • Service方法事务失效的原因是什么?
  • 2025-08-21 Python进阶8——命名空间作用域
  • PiscCode实现MediaPipe 的人体姿态识别:三屏可视化对比实现
  • 算法题Day4
  • WaitForSingleObject函数详解
  • JavaScript 性能优化实战技术文章大纲
  • C++手撕LRU
  • 中国之路 向善而行 第三届全国自驾露营旅游发展大会在阿拉善启幕
  • Webpack的使用
  • 5.Shell脚本修炼手册---Linux正则表达式(Shell三剑客准备启动阶段)
  • AI 时代的 “人机协作”:人类与 AI 如何共塑新生产力
  • 7.Shell脚本修炼手册---awk基础入门版
  • camel中支持的模型与工具
  • 爬虫基础学习-POST方式、自定义User-Agent
  • FCN网络结构讲解与Pytorch逐行讲解实现
  • 小程序个人信息安全检测技术:从监管视角看加密与传输合规
  • 限流技术:从四大限流算法到Redisson令牌桶实践
  • SpringBoot整合HikariCP数据库连接池
  • 机器学习聚类算法
  • 【机器学习】线性回归