原题:题目链接
给定一个二叉树,原地将它展开为链表。
例如,给定二叉树
将其展开为:
解法一
根据栗子中的顺序不难看出就是一个加上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
后续可能还会更新其他方法,上述代码或解释如果有问题还希望不吝指出,谢谢!
请原谅以往无知的自己吧,你毕竟拥有了现在,干就完事了!!!