109 - 有序链表转换二叉搜索树 - python

155 阅读2分钟

给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

给定的有序链表: [-10, -3, 0, 5, 9],

一个可能的答案是:[0, -3, 9, -10, null, 5], 它可以表示下面这个高度平衡二叉搜索树:

      0
     / \
   -3   9
   /   /
 -10  5

该题和108 - 将有序数组转换为二叉搜索树 - python唯一一点不同的地方在于这里给定的是链表形式的元素集合。因此,一种方法便是首先遍历链表中的每个节点,并存储对应的值,最后按照上一题的方法构建高度平衡的二叉搜索树即可。

class Solution:
    def sortedListToBST(self, head: ListNode) -> TreeNode:
        if not head: return None

        # 优化的地方在于如何得到中序遍历序列的中点
        r = []
        while head:
            r.append(head.val)
            head = head.next

        def buildTree(nums):
            if nums == []: return None
            if len(nums) == 1: return TreeNode(nums[0])

            mid = len(nums) // 2
            root = TreeNode(nums[mid])
            root.left = buildTree(nums[:mid])
            root.right = buildTree(nums[mid + 1:])

            return root

        return buildTree(r)

除了直接借用上一题的方法来解决外,如果我们不提前将链表的元素存放在数组中,那就需要在递归构建子树的过程中实时的计算中点的位置。而链表中点的位置可以通过双指针法,即快慢指针slowPtrfastPtr来解决。

  • 首先,slowPtrfastPtr都指向链表的开始位置,然后slowPtr每次走一步,fastPtr每次走两步,当fastPtr到达链表尾部时,slowPtr所处的位置就是所求的中点位置

  • 中点左边的链表即左子树对应的元素,中点右边的链表为右子树对应的元素,利用中点指向的根节点元素和左右子树的链表构建此时的二叉搜索树

  • 递归进行上述过程,直到到达叶子节点为止


    在这里插入图片描述


class Solution:

    def findMiddle(self, head):

        prevPtr = None
        slowPtr = head
        fastPtr = head
        while fastPtr and fastPtr.next:
            prevPtr = slowPtr
            slowPtr = slowPtr.next
            fastPtr = fastPtr.next.next
		# 断链
        if prevPtr:
            prevPtr.next = None

        return slowPtr

    def sortedListToBST(self, head):
        if not head: return None

        mid = self.findMiddle(head)
        node = TreeNode(mid.val)

        if head == mid:
            return node

        node.left = self.sortedListToBST(head)
        node.right = self.sortedListToBST(mid.next)
        
        return node