LeetCode 114.二叉树展开为链表(Python实现)

二叉树展开为链表

题目给定一个二叉树,要求原地将它展开为链表。
例如,给定二叉树
LeetCode 114.二叉树展开为链表(Python实现)
将其展开为:
LeetCode 114.二叉树展开为链表(Python实现)

题目解读

在Python中,树的实现一般为:

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

而链表的实现形式为:

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

也就是说,在本题中,我们要通过某种方式将树中所有节点的左子树都接到右子树的位置,然后令左子树为None。最后,所有的节点都会表现为左子树为None,右子树相连的情况,以此代替链表中的self.next 。

代码解析

下面我们来结合代码,分析一下这是怎么实现的。

    def flatten(self, root: TreeNode) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        # 鲁棒性
        if not root:
            return None
        # 递归(后序遍历)
        self.flatten(root.left)
        self.flatten(root.right)
        if root.left:
        	#左树接右位
            right = root.right
            root.right = root.left
            root.left = None
            #右树接最后
            while root.right:
                root = root.right
            root.right = right

有很多刚接触递归的朋友都可能不太了解,下面这两句是什么意思。

        self.flatten(root.left)
        self.flatten(root.right)
  • 其实每层的递归到了这里就会进入下一层,这两行以下的代码在这个过程中完全不会触发
  • 直到最后一层触发了鲁棒性条件,才会回来,实际上是一个从上到下再到上的过程
  • 那么这里是不是很像二叉树的后序遍历呢?因为也是一个访问左右节点再向上的过程。

接下来的代码也不难理解,就是前面说的将左树移到右边,然后右树接到后面的过程。
有小伙伴可能又要问了,为什么不直接像以下这样操作呢?

        if root.left:
            temp = root.right
            root.right = root.left
            root.left = None
            root.right.right = temp

这不是刚好原来的右树接到原来左树后吗?我一开始写的时候也犯了这个错误,让我们来结合图示看一下。
LeetCode 114.二叉树展开为链表(Python实现)
第一次递归回去,好像是对的。
LeetCode 114.二叉树展开为链表(Python实现)
但第二次递归回去就明显不对了,这是因为我们将原来的右树直接接在原来的左树上,丢失了3和4节点。因此,我们要在这里加一个while循环,确保接到最后面的节点,即本题的节点4,这样才正确。