力扣每日一题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) 额外空间)展开这棵树吗?


面试中遇到过这道题?

1/5

通过次数

465.3K

提交次数

631.8K

通过率

73.6%

结点结构

/*** Definition for a binary tree node.* 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 {
public:void preorder(TreeNode *root,vector<TreeNode*> &temp){if(!root) return ;temp.push_back(root);preorder(root->left,temp);preorder(root->right,temp);}void flatten(TreeNode* root) {if(!root) return;vector<TreeNode*> temp;preorder(root,temp);temp.push_back(NULL);for(int i=0;i<temp.size()-1;i++){temp[i]->left=NULL;temp[i]->right=temp[i+1];}}
};

官解还提供了下面两种方法

方法二:前序遍历和展开同时进行

使用方法一的前序遍历,由于将节点展开之后会破坏二叉树的结构而丢失子节点的信息,因此前序遍历和展开为单链表分成了两步。能不能在不丢失子节点的信息的情况下,将前序遍历和展开为单链表同时进行?

之所以会在破坏二叉树的结构之后丢失子节点的信息,是因为在对左子树进行遍历时,没有存储右子节点的信息,在遍历完左子树之后才获得右子节点的信息。只要对前序遍历进行修改,在遍历左子树之前就获得左右子节点的信息,并存入栈内,子节点的信息就不会丢失,就可以将前序遍历和展开为单链表同时进行。

该做法不适用于递归实现的前序遍历,只适用于迭代实现的前序遍历。修改后的前序遍历的具体做法是,每次从栈内弹出一个节点作为当前访问的节点,获得该节点的子节点,如果子节点不为空,则依次将右子节点和左子节点压入栈内(注意入栈顺序)。

展开为单链表的做法是,维护上一个访问的节点 prev,每次访问一个节点时,令当前访问的节点为 curr,将 prev 的左子节点设为 null 以及将 prev 的右子节点设为 curr,然后将 curr 赋值给 prev,进入下一个节点的访问,直到遍历结束。需要注意的是,初始时 prev 为 null,只有在 prev 不为 null 时才能对 prev 的左右子节点进行更新。

class Solution {
public:void flatten(TreeNode* root) {if (root == nullptr) {return;}auto stk = stack<TreeNode*>();stk.push(root);TreeNode *prev = nullptr;while (!stk.empty()) {TreeNode *curr = stk.top(); stk.pop();if (prev != nullptr) {prev->left = nullptr;prev->right = curr;}TreeNode *left = curr->left, *right = curr->right;if (right != nullptr) {stk.push(right);}if (left != nullptr) {stk.push(left);}prev = curr;}}
};

方法三:寻找前驱结点。(类似于Morris遍历)

前两种方法都借助前序遍历,前序遍历过程中需要使用栈存储节点。有没有空间复杂度是 O(1)O(1)O(1) 的做法呢?

注意到前序遍历访问各节点的顺序是根节点、左子树、右子树。如果一个节点的左子节点为空,则该节点不需要进行展开操作。如果一个节点的左子节点不为空,则该节点的左子树中的最后一个节点被访问之后,该节点的右子节点被访问。该节点的左子树中最后一个被访问的节点是左子树中的最右边的节点,也是该节点的前驱节点。因此,问题转化成寻找当前节点的前驱节点。

具体做法是,对于当前节点,如果其左子节点不为空,则在其左子树中找到最右边的节点,作为前驱节点,将当前节点的右子节点赋给前驱节点的右子节点,然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设为空。对当前节点处理结束后,继续处理链表中的下一个节点,直到所有节点都处理结束。

class Solution {
public:void flatten(TreeNode* root) {TreeNode *curr = root;while (curr != nullptr) {if (curr->left != nullptr) {auto next = curr->left;auto predecessor = next;while (predecessor->right != nullptr) {predecessor = predecessor->right;}predecessor->right = curr->right;curr->left = nullptr;curr->right = next;}curr = curr->right;}}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/7060.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

js方法返回类型

在JavaScript中&#xff0c;方法可以是以下几种形式&#xff1a; 1. **函数声明**&#xff1a;传统的函数声明方式。 javascript function greet() { console.log(Hello, World!); } 2. **函数表达式**&#xff1a;使用变量赋值的方式定义函数。 javascript const greet…

2024年CMS市场的份额趋势和使用统计

目前市面上有超过一半的网站都是使用CMS来搭建的&#xff0c;据不完全统计&#xff0c;现在大概有900多种CDM可供选择&#xff0c;以下是最常见的CMS的市场份额和使用率信息&#xff1a; 除了WordPress以外&#xff0c;Shopify和Wix也是比较流行的内容管理系统&#xff0c;尤其…

239 基于matlab的EKF(扩展卡尔曼滤波)_UKF(无迹卡尔曼滤波)_PF(粒子滤波)三种算法的估计结果比较

基于matlab的EKF(扩展卡尔曼滤波)_UKF(无迹卡尔曼滤波)_PF&#xff08;粒子滤波&#xff09;三种算法的估计结果比较&#xff0c;输出估计误差&#xff0c;并单独对粒子滤波进行估计及其置信区间可视化。程序已调通&#xff0c;可直接运行。 239 EKF(扩展卡尔曼滤波) - 小红书 …

php 修改 文件权限 函数chmod()

目录 前言 前言 在PHP中&#xff0c;你可以使用chmod()函数修改文件的权限。该函数接受两个参数&#xff1a;文件路径和新的权限模式。以下是一个示例&#xff1a; php <?php // 文件路径 $filename example.txt;// 新的权限模式&#xff08;例如&#xff1a;0644&#…

一、Redis五种常用数据类型

Redis优势&#xff1a; 1、性能高—基于内存实现数据的存储 2、丰富的数据类型 5种常用&#xff0c;3种高级 3、原子—redis的所有单个操作都是原子性&#xff0c;即要么成功&#xff0c;要么失败。其多个操作也支持采用事务的方式实现原子性。 Redis特点&#xff1a; 1、支持…

【Linux】操作系统

上一篇博客我们从硬件的角度谈了计算机&#xff0c;我们说到了计算机的效率跟操作系统写的好不好有着直接的关系&#xff0c;那么这篇博客我们从软件的角度&#xff0c;就来谈一谈究竟什么是操作系统&#xff0c;为什么要有操作系统&#xff1f; 首先我们来大体的认识一下操作…

某塑料科技公司网络与机房监控运维项目

某塑料科技公司是由日本知名株式会社在中国投资的&#xff0c;以从事橡胶和塑料制品业为主的生产制造企业。随着企业信息化建设提速&#xff0c;信息化运用程度不断提高&#xff0c;对网络基础设施的管理也提出了更高要求&#xff0c;因此公司急需上线一款综合运维平台加强对整…

Go 语言 ORM 框架之 xorm

1、xorm 1.1、xorm 简介 xorm 是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 特性 支持 struct 和数据库表之间的灵活映射&#xff0c;并支持自动同步事务支持同时支持原始SQL语句和ORM操作的混合执行使用连写来简化调用支持使用ID, In, Where, Limit,…

Linux—-vim基础使用

1、基本概念 Vim的工作模式有四种&#xff0c;普通模式&#xff0c;输入模式&#xff0c;命令模式&#xff0c;可视模式。 在终端中打开vim&#xff0c;只需要输入vim 文件&#xff0c;在普通模式下按i就会进入到输入模式&#xff0c;按下:进入命令模式&#xff0c;输入:q就可…

【前端学习——防抖和节流+案例】

定义 【前端八股文】节流和防抖 防抖 连续触发事件但是在设定的一段时间内只执行最后一次 代码实现思路【定时器】 大概意思就是&#xff1a; 每次按起键盘后&#xff0c;都将之前的定时器删除&#xff0c;重新开始计时。 节流 连续触发事件&#xff0c;只执行一次 …

优化理论及应用导读

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言常用的优化理论类型介绍常用的优化方法求解优化问题的工具库二次型函数优化--二次型调节器理论nlopt库的使用OOQP二次优化库 …

Python从0到100(二十):文件读写和文件操作

一、文件的打开和关闭 有了文件系统可以非常方便的通过文件来读写数据&#xff1b;在Python中要实现文件操作是非常简单的。我们可以使用Python内置的open函数来打开文件&#xff0c;在使用open函数时&#xff0c;我们可以通过函数的参数指定文件名、操作模式和字符编码等信息…

Redis之字符串类型深入之SDS底层结构

作为一名程序员不可能不知道redis 知道redis不可能不知道redis的字符串 如果你真的熟悉redis不能不知道sds, 我们探究一下redis字符串的底层结构 sds翻译过来就是动态扩容(Simple Dynamic String)、先看一下最早版本redis的sds结构体 struct sdshdr{int len; //记录数组中…

某站戴师兄——Excel实战

1、设置下拉选项&#xff1a;数据——数据验证——设置 如下设置&#xff1a; 2、If、sumif、index、match综合应用&#xff1a; sumif(条件区域&#xff0c;条件&#xff0c;目标区域&#xff09; sumifs(目标区域,条件区域1&#xff0c;条件1,条件区域2&#xff0c;条件2) …

Telnet的三种配置和SSH配置

Telnet的三种配置 实验配置思路&#xff1a; 配置接口IP地址&#xff1a; R1——配置接口IP地址 R2——配置接口IP地址 认证模式为none的配置 R1——认证模式配置为none R2——测试Telnet连接R1设备 认证模式为passwrd的配置 R1——认证模式配置为password R2——测试Telnet连…

19 内核开发-内核源码编译

19 内核开发-内核源码编译 (1)开始准备 安装好virtual box ubuntu 系统后&#xff0c;即可下载内核代码&#xff0c;进行编译 历史内核源码地址&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/kernel/v5.x/ 下载 linux-5.10.102.tar.gz 的包,可以使用wget 命令 创建编译目…

docker的介绍及使用--解决应用程序的环境配置问题

系列文章目录 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 TODO:写完再整理 文章目录 系列文章目录前言docker的介绍及使用参考资料前言 认知有限,望大家多多包涵,有什么问题也希望能够与大家多交流,共同成长! 本文先对docker的介绍及使用–解决…

FR在开发组件时的注意事项

FR目前可以在三个地方开发自己的组件&#xff0c;普通报表参数面板上&#xff0c;普通报表填报下&#xff0c;决策系统中。 其中普通报表参数面板&#xff0c;决策系统中开发组件的属性是返回 CRPropertyDescriptor[] supportedDescriptor() 这种方式是提供属性的名字&#x…

Linux字符设备驱动(二) - 与设备驱动模型的关系

一&#xff0c;从/dev目录说起 从事Linux嵌入式驱动开发的人&#xff0c;都很熟悉下面的一些基础知识&#xff0c; 比如&#xff0c;对于一个char类型的设备&#xff0c;我想对其进行read wirte 和ioctl操作&#xff0c;那么&#xff1a; 1&#xff09;我们通常会在内核驱动中…

分数排序 内存限制: 256 Mb时间限制: 1000 ms

题目描述 给定正整数 n 与 k, 将分母范围在 1 到 n 之间的所有最简真分数排序, 请输出其中第 k 小的分数。 输入格式 两个整数 n 与 k, 保证 k 是一个合理的参数, 即保证分母不超过 n 的最简真分数至少有 k 个。 输出格式 一个分数,形如 A/B, A 与 B 分别表示分…