面试经典150题——二叉树展开为链表

ops/2024/11/9 16:40:53/

white and blue surfboard on beach during daytime

1. 题目描述

image-20240422220201508

2.  题目分析与解析

2.1 思路一

因为题目中提到:展开后的单链表应该与二叉树 先序遍历 顺序相同,那么我们是不是就可以先先序遍历,然后按照先序遍历的节点一个一个赋值?

其实最简单的思路就是用一个结构按顺序存储所有先序遍历的结果,然后一个一个进行连接,但是这样空间复杂度为O(n),因为这种思路比较简单就不过多赘述了。

我在这里提出的思路是在先序遍历的过程中,进行链表的构建。如果按照这种思路,听起来好像没什么问题,但是如果我进行先序遍历,首先遍历根节点,需要把左节点置空,就会出现下面的情况:

image-20240423100605336

可以看到5,6节点断掉了。所以我们就得用一个结构存储那些断掉的部分,又因为在先序遍历中最先断掉的部分会在遍历过程中也最后被遍历到,所以我们可以使用栈,利用栈的先进后出,存储断掉的部分。这样就有下面的情况:

image-20240423102221202

然后这时左边节点发现遍历完毕之后,从栈中取出栈顶4号节点,继续进行上述操作:

image-20240423105601522

整体思路:

  1. 按照前序遍历的顺序,用栈存储丢失的右子树节点

  2. 递归构建左子树的链表

  3. 从栈中取出节点递归构建右子树的链表

2.2 思路二

参考windliang - 力扣(LeetCode)

因为题目中提到了

image-20240423104842927

那么我们就要想办法把这个栈空间给省略掉,所以我们首先要弄清楚栈到底存的什么东西。其实栈就是不断地存储那些被丢失的右节点。

右节点?既然我们担心右节点丢失,那么我们就可以先把右节点是不是先放在二叉树的某个位置,保存起来,这样就不需要再用栈来额外存储这些右节点了。那到底存储在哪呢?先看一下结果:

img

我们可以发现右节点总是在左子树的最右节点的后面,对应上图就是 5在4后面——对应1的左子树最右边一个节点为4,4在3后面——对应2的左子树最右边一个节点为3(因为2的左子树就只有3)。对应图解为:

image-20240423112000454

因此我们是不是可以先把右子树存储在左子树最右边一个节点的后面,这样就不需要栈来存储了。现在我们就需要考虑怎么找到左子树的最右边一个节点,然后把右子树接到这个节点后面。之后再看root.right下一个节点,以此类推就可求解。

整体思路:

  1. 将左子树插入到右子树的地方

  2. 将原来的右子树接到左子树的最右边节点

  3. 考虑新的右子树的根节点,一直重复上边的过程,直到新的右子树为 null

2.3 思路三

现在还是抓住问题的本质,我们需要省略掉栈保存的右节点。上面思路二的想法是用左子树的最右节点来临时存储右子树,那么我们可不可以从后往前去遍历,先遍历右子树的部分,然后把这部分的根节点这一个节点存储起来,再遍历左子树,也就是按照后序遍历的变种右子树->左子树->根节点的方式进行处理。

后序遍历(Postorder Traversal):先递归地后序遍历左子树,然后递归地后序遍历右子树,最后访问根节点。

具体步骤:

  1. 递归地后序遍历左子树。

  2. 递归地后序遍历右子树。

  3. 访问根节点。

我们依次遍历 6 5 4 3 2 1,然后每遍历一个节点就将当前节点的右指针更新为上一个节点。

遍历到 5,把 5 的右指针指向 6。6 <- 5 4 3 2 1。

遍历到 4,把 4 的右指针指向 5。6 <- 5 <- 4 3 2 1。

按照这样的方式我们只需要一个临时变量存储前序节点就可以了。

3. 代码实现

3.1 思路一

image-20240423104809614

image-20240423104544306

3.2 思路二

image-20240423112845424

image-20240423112832413

3.3 思路三

image-20240423114600786

image-20240423114432394

4. 相关复杂度分析

  1. 解法一:使用递归和栈

    • 时间复杂度:O(n),其中 n 是二叉树中的节点数。递归函数 createLinkedList 遍历了每个节点一次。

    • 空间复杂度:O(h),其中 h 是二叉树的高度。在最坏情况下,栈的深度为 h,即二叉树的高度。

  2. 解法二:迭代方法

    • 时间复杂度:O(n),其中 n 是二叉树中的节点数。每个节点最多被访问两次。

    • 空间复杂度:O(1)。没有使用额外的空间,只使用了常数级别的额外空间。

  3. 解法三:使用递归和全局变量

    • 时间复杂度:O(n),其中 n 是二叉树中的节点数。递归函数 postOrder 遍历了每个节点一次。

    • 空间复杂度:O(h),其中 h 是二叉树的高度。递归调用栈的深度取决于二叉树的高度。

image-20240301121908772


http://www.ppmy.cn/ops/13227.html

相关文章

MySQL-锁篇

文章目录 表级锁和行级锁了解吗&#xff1f;有什么区别&#xff1f;行级锁使用有什么注意事项&#xff1f;InnoDB有哪几类行锁&#xff1f;共享锁和排他锁是什么&#xff1f;意向锁有什么用&#xff1f; 锁是一种常见的并发事务的控制方式 表级锁和行级锁了解吗&#xff1f;有什…

云计算时代,企业面临的云安全风险

如今&#xff0c;随着云计算等新兴科技的发展&#xff0c;不同类型企业间的关联越来越多&#xff0c;它们之间的业务边界已被打破&#xff0c;企业上云成为了大势所趋。云计算应用帮助企业改变了IT资源不集中的状况&#xff0c;同时&#xff0c;数据中心内存储的大量数据信息&a…

uniapp制作多选下拉框和富文本(短信页面)

实例 多选下拉框实现 http://t.csdnimg.cn/TNmcF 富文本实现 http://t.csdnimg.cn/Ei1iV

面试经典150题——分发糖果

面试经典150题 day15 题目来源我的题解方法一 两次不同方向的遍历&#xff08;应该是贪心&#xff09;方法二 贪心 题目来源 力扣每日一题&#xff1b;题序&#xff1a;135 我的题解 方法一 两次不同方向的遍历&#xff08;应该是贪心&#xff09; 遍历两次&#xff08;左→…

网络安全事件频发,让态势感知来提前洞察快速防护

一、引言 随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显&#xff0c;成为社会各界普遍关注的焦点。近年来&#xff0c;网络安全事件频发&#xff0c;给个人、企业乃至国家带来了严重的损失。这些事件不仅揭示了网络安全领域的严峻挑战&#xff0c;也敲响了信息安全…

甘特图是什么?如何利用其优化项目管理流程?

甘特图是项目管理软件中十分常见的功能&#xff0c;可以说每一个项目经理都要学会使用甘特图才能更好的交付项目。什么是甘特图&#xff1f;甘特图用来做什么&#xff1f;简单来说一种将项目任务与时间关系直观表示的图表&#xff0c;直观地展示了任务进度和持续时间。 一、甘特…

基于HMM隐马尔可夫模型的金融数据预测算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于HMM隐马尔可夫模型的金融数据预测算法.程序实现HMM模型的训练&#xff0c;使用训练后的模型进行预测。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运…

C++:范围-based for 循环

范围-based for 循环是 C11 引入的一种循环语法&#xff0c;它简化了遍历容器和数组等序列的操作&#xff0c;使代码更加清晰和简洁。它通常用于遍历容器类&#xff08;如数组、向量、列表等&#xff09;中的元素&#xff0c;或者以范围的形式遍历初始化列表。 范围-based for …