题目
给你二叉树的根结点 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]
分析
为了解决将二叉树展开为与先序遍历顺序相同的单链表这一问题,可以使用递归的方法。递归地处理左子树和右子树,然后将它们连接起来形成单链表。
递归
时间复杂度:O(),
是二叉树的节点数
空间复杂度:O()
class Solution {
public:
void flatten(TreeNode* root) {
if (root == nullptr) return;
// 递归处理左子树和右子树
flatten(root->left);
flatten(root->right);
// 保存当前节点的右子树
TreeNode* rightSubtree = root->right;
// 将左子树移到右边
root->right = root->left;
root->left = nullptr;
// 找到当前节点新的右子树的最右节点
TreeNode* current = root;
while (current->right != nullptr) {
current = current->right;
}
// 将原来的右子树连接到新的右子树的最右节点
current->right = rightSubtree;
}
};
空间优化
如果要满足空间复杂度为 O(1),我们可以使用 Morris 遍历的思想。Morris 遍历是一种空间复杂度为 O(1) 的二叉树遍历方法,它通过利用树中的空闲指针来实现。
时间复杂度:O(),
是二叉树的节点数
空间复杂度:O(1)
class Solution {
public:
void flatten(TreeNode* root) {
TreeNode* current = root;
while (current!= nullptr) {
if (current->left!= nullptr) {
// 找到当前节点左子树的最右节点
TreeNode* pre = current->left;
while (pre->right!= nullptr) {
pre = pre->right;
}
// 将当前节点的右子树接到左子树的最右节点的右子树上
pre->right = current->right;
// 将当前节点的左子树接到当前节点的右子树上
current->right = current->left;
// 左子树设为nullptr
current->left = nullptr;
}
// 移动到当前节点的右子树
current = current->right;
}
}
};