LeetCode 114 Flatten Binary Tree to Linked List的多种解法分析 Python3

原题:题目链接
给定一个二叉树,原地将它展开为链表。
例如,给定二叉树
在这里插入图片描述
将其展开为:
在这里插入图片描述

解法一

根据栗子中的顺序不难看出就是一个加上null左儿子的先序遍历。因此我考虑使用非递归版本的先序遍历的思想,利用O(n)的空间创建一个栈来保存要操作的节点。可能有人会说创建创建一个栈保存节点不满足题目要求的in-place。但就个人理解而言,我认为是符合题意的,树的结构并没有被破坏,而栈只是保存的节点地址而已。因此代码如下:

	def flatten(root):
		if not root:
			return
		# 设置一个哨兵节点
		s = TreeNode(-1)
		# 初始化
		preNode = s
		# 堆栈
		stack = [root]
		while len(stack) != 0:
			curNode = stack.pop()
			# 将当前节点设为前一个节点的right child 并将left child置空
			preNode.right = curNode
			preNode.left = None
			# 先序堆栈放入顺序
			if curNode.right:
				stack.append(curNode.right)
			if curNode.left:
				stack.append(curNode.left)
			# 更新节点
			preNode = curNode

解法二

事实上,我们还可以从以下思路出发来逐渐改变二叉树的结构。
为了实现所谓的右展开,将左子树直接换到右子树即可,为了避免这样直接操作导致右子树被替换消失,先将右子树拼接到左子树的最右节点处,然后再把左子树换过去,直到遍历到最后一个节点退出。

	def flatten(root):
		# 保存root
		temp = root
		while temp:
			# 左子树最右节点初值
			rightestNode = temp.left
			# 没有左儿子 则考虑下一个右节点
			if not rightestNode:
				temp = temp.right
				continue
			# 搜索最右节点
			while rightestNode:
				rightestNode = rightestNode.right
			# 右子树拼接
			rightestNode.right = temp.right
			# 左子树换过去
			temp.right = temp.left
			temp.left = None

解法三

由于返回结果与先序遍历存在很大的关系,为此我们也可以考虑一种递归、简洁的实现方式。仔细思考会发现,单纯仅仅按照先序递归的套路似乎不可行,因为在左子树替换到右子树的时候会损失节点的信息,为此我们可以换一种思路,相当于一种先序遍历的逆,即先考虑右节点,然后考虑左节点,最后考虑根,并在此间递归返回的之前完成右儿子的赋值以及节点的更新,类似于自底向上的感觉(可能不专业 - 0 -)。

	def flatten(root):
		# 全局变量
		preNode = None
		def dfs(root):
			if not root:
				# 如果为空直接返回
				return
			# 先考虑右节点
			dfs(root.right)
			# 再考虑左节点
			dfs(root.left)
			# 右儿子赋值 左儿子置空
			root.right = preNode
			root.left = None
			# 递归返回之前更新节点
			nonlocal preNode
			preNode = root			

后续可能还会更新其他方法,上述代码或解释如果有问题还希望不吝指出,谢谢!

请原谅以往无知的自己吧,你毕竟拥有了现在,干就完事了!!!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Key Board

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值