给定一个单链表,其中的元素按升序排序,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 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)
除了直接借用上一题的方法来解决外,如果我们不提前将链表的元素存放在数组中,那就需要在递归构建子树的过程中实时的计算中点的位置。而链表中点的位置可以通过双指针法,即快慢指针slowPtr
和fastPtr
来解决。
-
首先,
slowPtr
和fastPtr
都指向链表的开始位置,然后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