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

原题:题目链接
给定一个二叉树,原地将它展开为链表。
例如,给定二叉树
LeetCode 114 Flatten Binary Tree to Linked List的多种解法分析 Python3_第1张图片
将其展开为:
LeetCode 114 Flatten Binary Tree to Linked List的多种解法分析 Python3_第2张图片

解法一

根据栗子中的顺序不难看出就是一个加上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			

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

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

你可能感兴趣的:(LeetCode刷题)