题目描述
给你二叉树的根结点 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
递归后序遍历
核心思路
核心思路采用递归后序遍历:
- 递归展开左右子树
- 将左子树插入根节点与右子树之间
- 遍历至新链表末端连接右子树
代码实现
1 | public void flatten(TreeNode root) { |
算法流程详解
- 递归终止:当前节点为
null
时返回 - 后序遍历:
- 先递归处理左子树(
flatten(root.left)
) - 再递归处理右子树(
flatten(root.right)
)
- 先递归处理左子树(
- 链表重组:
- 保存当前左右子树引用
- 将左子树作为新的右子树(
root.right = left
) - 遍历新右子树找到末端节点
- 将原右子树接在末端节点后
关键步骤图示
1 | 原始结构: |
复杂度分析
- 时间复杂度:
O(n)
,每个节点被访问两次,递归展开时访问一次,寻找链表末端时访问一次。 - 空间复杂度:
O(n)
,递归栈深度取决于树的高度,最坏情况(链状树)空间复杂度为O(n)
,平衡树情况为O(logn)
。
关键点总结
- 后序遍历顺序:必须保证左右子树都已展开成链表后才能进行根节点的重组。
- 链表拼接细节:左子树插入后需遍历到末端再连接右子树,注意切断左指针避免结构混乱。
- 原地修改:直接修改节点指针,不新建数据结构。