LeetCode 面试经典 150_二叉树_二叉树展开为链表(74_114_C++_中等)
题目描述:
给你二叉树的根结点 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、在进行先序遍历的时候先将结点的信息存储到数组中,通过数组中的先后顺序更新每个结点的指向。
2、复杂度分析:
① 时间复杂度:O(n),n为二叉树中节点的个数,需遍历一遍二叉树O(n),遍历一遍数组更改指针的指向O(n)。
② 空间复杂度:O(n),递归遍历所需空间最多为O(n),一个额外的数组存储二叉树的信息O(n)。
思路二(先序遍历(非递归)):
1、如果我们采用非递归的方式,当我们遍历到一个结点时,我们就可以用一个指针来记录先序遍历中上一个结点的信息,通过修改上一个结点的指向来转换成单链表。
3、复杂度分析
① 时间复杂度:O(n),n为二叉树中节点的个数,需遍历一遍二叉树O(n)。
② 空间复杂度:O(n),先序遍历的非递归实现需要借助栈实现,最坏情况下栈中有n个结点信息。
代码实现
代码实现(思路一(先序遍历(递归+数组))):
cpp
//方法一(递归):采用递归的前序遍历将遍历的结点存储在数组中,然后修改指针的指向
class Solution1 {
private:
//先序遍历将结点信息存储在nums_TreeNode中
//注意vector<TreeNode *>&nums_TreeNode这里的引用(&)
void preorder(TreeNode *root,vector<TreeNode *>&nums_TreeNode){
if(root==nullptr) return;
nums_TreeNode.emplace_back(root);
preorder(root->left,nums_TreeNode);
preorder(root->right,nums_TreeNode);
}
public:
void flatten(TreeNode* root) {
//nums_TreeNode存放先序遍历各节点的顺序
vector<TreeNode *>nums_TreeNode;
//先序遍历将结点信息存储在nums_TreeNode中
preorder(root,nums_TreeNode);
//根据nums_TreeNode中结点的顺序更改结点的指向
for (int i = 1; i < nums_TreeNode.size(); i++)
{
nums_TreeNode[i-1]->left=nullptr;
nums_TreeNode[i-1]->right=nums_TreeNode[i];
}
}
};
代码实现(思路二(先序遍历(非递归))):
cpp
//方法二:非递归先序遍历,pre代表当前遍历结点的前一个结点,改变pre左右孩子结点的指向
class Solution2 {
public:
void flatten(TreeNode* root) {
if(root==nullptr) return ;
stack<TreeNode *>stk;
stk.push(root);
//存放展开单链表的末尾
TreeNode *tail=nullptr;
while (!stk.empty())
{
TreeNode *node=stk.top();
stk.pop();
//更改结点的指向
if(tail!=nullptr) {
tail->left=nullptr;
tail->right=node;
}
//注意右子结点先入栈
if(node->right!=nullptr) stk.push(node->right);
if(node->left!=nullptr) stk.push(node->left);
//更新单链表的尾结点
tail=node;
}
}
};
以思路一为例进行调试
cpp
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
struct TreeNode
{
int val;
TreeNode *left;
TreeNode *right;
TreeNode():val(0),left(nullptr),right(nullptr){}
TreeNode(int val):val(val),left(nullptr),right(nullptr){}
TreeNode(int val,TreeNode *left,TreeNode *right):val(val),left(left),right(right){}
};
//通过数组创建二叉树,数组中-1代表nullptr
TreeNode *createTree(vector <int> nums){
if (nums.empty()) return nullptr;
TreeNode *root=new TreeNode(nums[0]);
queue<TreeNode *> q;
q.push(root);
int i=1;
while (i<nums.size())
{
//注意这里不能用root,会改变root的指向
TreeNode *node=q.front();
q.pop();
if(i<nums.size()&&nums[i]!=-1){
node->left=new TreeNode(nums[i]);
q.push(node->left);
}
++i;
if(i<nums.size()&&nums[i]!=-1){
node->right=new TreeNode(nums[i]);
q.push(node->right);
}
++i;
}
return root;
}
//中序遍历输出二叉树,用于验证二叉树是否创建正确
void inorder_Traversal(TreeNode *root){
if(root==nullptr) return;
inorder_Traversal(root->left);
cout<<root->val<<" ";
inorder_Traversal(root->right);
}
class Solution1
{
public:
//方法一(递归):采用递归的前序遍历将遍历的结点存储在数组中,然后修改指针的指向
void flatten(TreeNode* root) {
vector<TreeNode *>nums_TreeNode;
preorder(root,nums_TreeNode);
for (int i = 1; i < nums_TreeNode.size(); i++)
{
nums_TreeNode[i-1]->left=nullptr;
nums_TreeNode[i-1]->right=nums_TreeNode[i];
}
}
//注意vector<TreeNode *>&nums_TreeNode这里的引用(&)
void preorder(TreeNode *root,vector<TreeNode *>&nums_TreeNode){
if(root==nullptr) return;
nums_TreeNode.emplace_back(root);
preorder(root->left,nums_TreeNode);
preorder(root->right,nums_TreeNode);
}
};
int main(){
vector<int> nums={1,2,5,3,4,-1,6};
//通过数组创建二叉树,-1为nullptr
TreeNode* root=createTree(nums);
//测试二叉树是否创建正确
//inorder_Traversal(root);
//二叉树展开为链表
Solution1 s;
s.flatten1(root);
//输出转换的单链表
while (root!=nullptr)
{
cout<<root->val<<"->";
root=root->right;
}
cout<<"nullptr";
return 0;
}
LeetCode 面试经典 150_二叉树_二叉树展开为链表(74_114)原题链接
欢迎大家和我沟通交流(✿◠‿◠)