LeetCode 114.二叉树展开为链表
Algorithm]
- 114. 二叉树展开为链表
- 🏛 问题
- 🎮 示例
- 示例 1
- 示例 2
- 示例 3
- 🛠️ 解法思路
- 🔗 方法:递归 / 原地修改(最优解之一)
- 🧠 直观解释
- ⚙️ C++ 实现
- ⚡ 复杂度分析
- ✅ 总结
114. 二叉树展开为链表
🏛 问题
给你二叉树的根节点 root
,请你将它 原地展开 为一个单链表:
- 展开后依然用
TreeNode
作为节点类型; - 链表通过节点的 right 指针 连接;
- 每个节点的 left 指针都要置为 null;
- 链表的顺序必须与 二叉树的先序遍历顺序 相同。
🎮 示例
示例 1
输入:
1/ \2 5/ \ \3 4 6
输出链表:
1 → 2 → 3 → 4 → 5 → 6
示例 2
输入:[]
输出:[]
示例 3
输入:
0
输出:
0
🛠️ 解法思路
🔗 方法:递归 / 原地修改(最优解之一)
核心思想:
- 按 先序遍历(根 → 左 → 右)顺序,把树改造成链表。
- 对于每个节点:
- 先把左子树展开为链表;
- 把右子树展开为链表;
- 把左子链表插到当前节点和右子链表之间。
伪代码:
function flatten(root):if root is null: returnflatten(root.left)flatten(root.right)tmp = root.rightroot.right = root.leftroot.left = null# 找到新右子树的最后一个节点p = root.rightwhile p is not null and p.right is not null:p = p.rightif p is not null:p.right = tmp
🧠 直观解释
- 先递归展开左子树和右子树;
- 把左子树整体挂到右边;
- 然后再把原来的右子树接到新链表的最后。
就像把左边那条“小链表”塞到右边去,再接上原右链表。
⚙️ C++ 实现
struct TreeNode {int val;TreeNode *left;TreeNode *right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};class Solution {
public:void flatten(TreeNode* root) {if (!root) return;// 递归展开左子树和右子树flatten(root->left);flatten(root->right);// 暂存右子树TreeNode* tmp = root->right;// 把左子树挂到右边root->right = root->left;root->left = nullptr;// 找到新右子树的末尾TreeNode* p = root->right;while (p && p->right) {p = p->right;}// 接回原右子树if (p) {p->right = tmp;} else {root->right = tmp;}}
};
⚡ 复杂度分析
-
时间复杂度:
每个节点都会被访问一次,另外在“寻找新右子树的末尾”时最坏可能 O(n),但整个树加起来仍是 O(n)。
👉 因为每条边最多被“走一次”,总共 O(n)。
-
空间复杂度:
递归调用深度等于树高。
- 最好情况(平衡二叉树):O(log n);
- 最坏情况(链式二叉树):O(n)。
✅ 总结
- 题目要求把树“拉直”成链表,顺序等于先序遍历。
- 关键在于:递归展开左右子树 → 左子树接到右边 → 原右子树接到新链表尾部。
- 时间 O(n),空间 O(h)。