LeetCode 面试经典 150_二叉树_二叉树展开为链表(74_114_C++_中等)

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)原题链接

欢迎大家和我沟通交流(✿◠‿◠)

相关推荐
夏幻灵5 小时前
JavaScript this 面试:五种绑定规则、优先级与常见面试陷阱
开发语言·javascript·面试
程序猿编码5 小时前
榨干 RTX5090 算力!Qwen3 专用单卡推理引擎,手写C++/CUDA 算子实现 MTP 推测解码
开发语言·c++·大模型推理·qwen3·多模态推理
西飘客6 小时前
vs 怎么根据dll 生成lib文件
c++·qt
程序员老陆7 小时前
深入理解 C++ thread_local:线程私有存储的正确打开方式
开发语言·c++·程序设计
夏幻灵8 小时前
LeetCode 21:合并两个有序链表——双指针与哑节点详解
算法·leetcode·链表
Navigator_Z10 小时前
LeetCode //C - 1286. Iterator for Combination
c语言·算法·leetcode
半杯咖啡半行码10 小时前
C++ 编程与 STL 模板:从泛型编程到内存安全详解
开发语言·c++
时间的拾荒人11 小时前
Qt 界面优化:绘图详解 —— 从基础图形到图片处理
开发语言·qt·面试
圣保罗的大教堂11 小时前
leetcode 301. 删除无效的括号 困难
leetcode
xh didida11 小时前
Linux -- 基础IO
linux·服务器·开发语言·c++