题目14: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]
示例 2:
输入:root = []
输出:[]
示例 3:
输入:root = [0]
输出:[0]
提示:
- 树中结点数在范围
[0, 2000]内 -100 <= Node.val <= 100
进阶: 你可以使用原地算法(O(1) 额外空间)展开这棵树吗?
思路分析
先说结论:后续遍历,使用pre记录上一个遍历的节点,当前节点cur->right = pre; cur->left = nullptr 即可以使用O(1) 的空间复杂度完成。
后续遍历:注意此后续遍历是先遍历右子树
- 右子树
- 左子树
- 根
程序代码
方法一:
// https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/description/
//https://leetcode.cn/problems/flatten-binary-tree-to-linked-list/description/
//114. 二叉树展开为链表
#include<iostream>
#include<vector>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
private:
// 前驱节点
TreeNode *pre = nullpth;
public:
void flatten(TreeNode* root) {
if(root == nullptr)
{
return;
}
// 右子树
flatten(root->right);
// 左子树
flatten(root->left);
// 把当前节点的右孩子指向 前驱
root->right = pre;
// 左孩子为空
root->left = nullptr;
pre = root;
}
};
复杂度分析
时间复杂度:O(n),其中 n 是二叉树中的节点个数。每个节点都会遍历一次。
空间复杂度:O(1) ,不算递归栈的情况下。
思路分析
把二叉树看成链表,先找前驱节点
1)如果当前节点左子节点不为空,则在其左子树中找到最右边的节点作为前驱节点
- 前驱节点的右子节点 = 当前节点的右子节点
pre->right = cur->right - 当前节点的右子节点 = 当前节点的左子节点
cur->right = cur->left - 当前节点的左子节点设为空
cur->left = nullptr
2)如果没有左孩子,那么就直接满足题目要求,处理下一个节点即可
程序代码
方法二:
class Solution {
public:
void flatten(TreeNode* root) {
TreeNode *curr = root;
while (curr != nullptr) {
if (curr->left != nullptr) {
TreeNode * pre = curr->left;
// 找到最右节点,作为前驱
while (pre->right != nullptr) {
pre = pre->right;
}
pre->right = curr->right;
curr->right = curr->left;
curr->left = nullptr;
}
// 如果没有左孩子,那么就直接满足题目要求,处理下一个节点即可
curr = curr->right;
}
}
};
复杂度分析
时间复杂度:O(n),其中 n 是二叉树中的节点个数。查找前驱过程中,每个节点最多多访问一次。
空间复杂度:O(1)
题目感悟
更多相关知识:github.com/pingguo1987…