LeetCode 109 有序链表转换二叉搜索树 Python3

原题: 链接

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

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

示例:
在这里插入图片描述
解答之前需要明白三个点:

  1. 链表是有序的
  2. 高度平衡的二叉搜索树
  3. 肯定用递归做简单地多
解法一

不难得知该树的根节点位于有序链表的中间位置。因此需要实现一个取出有序链表中间节点的算法,然后依次对取出的左半部分和右半部分递归执行类似的build tree操作。查找中间节点就是利用快慢指针法的一种自然的想法就是将链表斩断。由于链表不能像数组那样方便取值索引,因此在查找中间节点的时候,顺便保留中间节点的前一个节点,方便递归的时候直接拿过去享用。看代码会清楚一点:

# 一个查找中间节点 并返回它前一个节点的程序
def findMiddle(head):
	pre, slow, fast = None, head, head
	while fast and fast.next:
		pre = slow
		slow = slow.next
		fast = fast.next.next
	# 返回前一个节点 和 中间节点
	return pre, slow
def sortedListToBST(head):
	# 递归退出条件
	if not head:
		return None
	# 只有一个节点的时候 也直接返回
	if not head.next:
		# 注意是返回树节点
		return TreeNode(head.val)
	pre, mid = findMiddle(head)
	if pre:
		# 斩断
		pre.next = None
	# 当下的根
	root = TreeNode(mid.val)
	# 递归
	root.left = sortedListToBST(head)
	root.right = sortedListToBST(mid.next)
	return root

此算法时间复杂度为O(nlogn),空间复杂度为O(logn)。

一种空间换时间的算法就是通过将链表保存为数组,从而简化每次递归的查找操作。

解法二
def sortedListToBST(head):
	arr = []
	# 转换为数组
	while head:
		arr.append(head)
		head = head.next
	def helper(left, right):
		if left >= right:
			return None
		mid = (left + right) >> 1
		# 注意前闭后开的处理
		root = TreeNode(mid.val)
		root.left = helper(left, mid)
		root.right = helper(mid+1, right)
		return root
	return helper(0, len(arr))

时间复杂度为O(n),空间复杂度也为O(n)。

解法三

我们联想到二叉树的中序遍历刚好也是满足升序,是否可以通过中序遍历的模板来解决重建二叉树的操作?

答案是肯定的。在递归形式的中序遍历下,每次处理的节点都和给定有序链表下的节点顺序相同。因此我们仅需要将某个节点有所建树(建立二叉树)的逻辑捋清楚了,然后将链表指向下一个节点即可,至于剩下的就交给递归去完成吧。

这就是二叉树递归中序遍历的魅力啊!

def sortedListToBST(head):
	s = 0
	# 基本逻辑同上面的算法
	# 也需要拿到链表的长度
	temp = head
	while temp:
		s += 1
		temp = temp.next
	def buildTree(left, right):
		# 保存上一次递归完成的head
		nonlocal head
		if left >= right:
			return None
		mid = (left + right) >> 1
		# 中序遍历模板
		leftNode = buildTree(left, mid)
		# 根节点
		root = TreeNode(head.val)
		root.left = leftNode
		# 当前节点处理完毕 指向下一个待处理的节点
		# 链表的有序保证了中序遍历恢复的正确性
		head = head.next
		root.right = buildTree(mid+1, right)
		return root
	return buildTree(0, s)

这是最好的算法了,其中时间复杂度为O(n),空间复杂度为O(logn)。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Key Board

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值