LeetCode 热题 HOT 100 第44天:“二叉树展开为链表”

本文介绍了如何将二叉树展开为一个单链表,遵循先序遍历顺序。提供了三种解决方案,包括先序遍历后再改造、迭代先序遍历同步展开以及使用Mirrors先序遍历方法。每种方法都详细解析了思路,特别是迭代同步展开和Mirrors方法,通过调整节点链接来完成树到链表的转换,且不额外占用空间。最后给出了完整的Java代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继续刷LeetCode 热题 HOT 100 的题目,并且在博客更新我的solutions。在csdn博客中我会尽量用文字解释清楚,相关Java代码大家可以前往我的个人博客jinhuaiyu.com中查看。
题目:二叉树展开为链表
给你二叉树的根结点 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) 额外空间)展开这棵树吗?

solution 1:先得到先序遍历再改
将二叉树展开为单链表之后,单链表中的节点顺序即为二叉树的先序遍历访问各节点的顺序。因此,可以对二叉树进行先序遍历,获得各节点被访问到的顺序。由于将二叉树展开为链表之后会破坏二叉树的结构,因此在先序遍历结束之后更新每个节点的左右子节点的信息,将二叉树展开为单链表。
用递归实现先序遍历很简单,递归方法为:先将子树的根节点放入遍历list,再分别对左右子树进行递归调用先序遍历,递归终止条件是到达叶子结点。
但这种方法不符合进阶要求,用了O(n)空间的辅助数组。

solution 2:先序遍历和展开同步进行
在递归时同步展开很难进行,我们采用迭代的先序遍历,首先介绍这里的迭代过程:
用一个栈维护讨论了父结点但还没讨论自身的左右孩子节点。先将root入栈。开始循环讨论,当栈空时遍历结束。
每轮循环中:
弹出栈顶元素为当前遍历节点,如果它的左右孩子不为空,则以先右后左的顺序入栈,这样在下一轮循环中,弹出的要不就是前置节点的左孩子,否则前置节点不存在左孩子,弹出最近的祖先节点的右孩子。
上面就是迭代实现先序遍历的方法,我们可以设置一个前置节点的指针,保存好先序遍历过程中的前驱,每轮循环弹出当前节点后,如果存在前驱,就按题目要求接到前驱的右孩子(左孩子置空)。用担心前驱的右孩子丢失,因为上一轮循环已经将右孩子放入栈中了。在每轮循环最后,更新前置节点为当前节点即可。
这样我们就实现了一边遍历一边改造。

solution 3:Mirrors先序遍历
对于先序遍历来说,用Mirrors找前驱节点十分容易,如果能找到啊前驱节点,那么我们也可以一边遍历一边重新连接,而且不需要额外辅助空间。
对于当前遍历节点cur来说,如果它没有左孩子,则下一个即将遍历节点就是它的右孩子,根据题目要求,左孩子置空,右孩子是下一个节点,可以得知,这种情况我们完全不用改造,直接遍历下一个节点(右孩子)即可。
如果cur有左孩子,那么它的右孩子的前驱节点应该是左子树中先序遍历的最后一个(就是左孩子一直找right最后一个不为null的节点),我们可以直接把cur的右孩子(不管是不是null)手动连到其前驱节点的右孩子上(按题目要求的单链表顺序),然后把cur的左孩子接到cur原来右孩子的位置上。至此,我们回到了上一种情况,此时直接遍历下一个节点(新的右孩子,原来的左孩子)即可。

Finally,带有详细注释的代码放在我的个人博客http://jinhuaiyu.com/leetcode-flatten-binary-tree-to-linked-list/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值