用独到见解剖析 LeetCode 109:有序链表转化二叉搜索树
2024-02-06 15:14:25
在 LeetCode 的殿堂里,109 号问题犹如一颗璀璨的明珠,考验着程序员的算法能力和数据结构功底。它要求我们根据一个有序链表,构建一棵平衡二叉搜索树。乍一看,这似乎是一项艰巨的任务,但深入剖析后,你会发现其中蕴含着算法之美。
本篇博文将以独树一帜的视角,为你揭示 LeetCode 109 的精髓。我们将跳脱传统的解题思路,从问题本质出发,探索两种截然不同的方法。在纵横交错的算法迷宫中,我们将寻觅最优路径,拨开迷雾,直击问题的核心。
方法一:遍历链表,构建有序数组
回忆 LeetCode 108,我们曾将有序数组转化为二叉搜索树。因此,我们可以先遍历链表,将每个节点的数据存入一个有序数组中。然后,再运用 LeetCode 108 的方法,将有序数组转化为二叉搜索树。这种方法简单直观,但时间复杂度为 O(n),其中 n 为链表的长度。
def sortedListToBST(head):
# 遍历链表,将数据存入数组
nums = []
while head:
nums.append(head.val)
head = head.next
# 将有序数组转化为二叉搜索树
return sortedArrayToBST(nums)
def sortedArrayToBST(nums):
if not nums:
return None
# 寻找中点,将数组分为左右两部分
mid = len(nums) // 2
root = TreeNode(nums[mid])
# 递归构建左右子树
root.left = sortedArrayToBST(nums[:mid])
root.right = sortedArrayToBST(nums[mid+1:])
return root
方法二:中序遍历链表,构建平衡二叉搜索树
方法一虽然简单,但时间复杂度较高。有没有一种更优的方法呢?答案是肯定的。我们可以利用有序链表的特性,直接构建一棵平衡二叉搜索树,而无需借助额外的数组。
中序遍历一个二叉搜索树,得到的序列是一个有序序列。因此,我们可以中序遍历链表,将节点一个一个插入到二叉搜索树中。由于每次插入都是保持树的平衡性的,因此这种方法的时间复杂度为 O(n log n),比方法一要优。
def sortedListToBST(head):
def helper(left, right):
if left > right:
return None
# 找到中点
mid = (left + right) // 2
# 递归构建左子树
left_node = helper(left, mid - 1)
# 构建当前节点
curr_node = TreeNode(head.val)
curr_node.left = left_node
# 移动指针
head.next = head.next.next
# 递归构建右子树
curr_node.right = helper(mid + 1, right)
return curr_node
# 初始化左右指针
left = 0
right = 0
# 计算链表长度
while head:
right += 1
head = head.next
return helper(left, right - 1)
结语
LeetCode 109 问题看似复杂,但通过巧妙的算法设计,我们可以找到高效的解决方案。方法一简单直观,而方法二则利用了有序链表的特性,实现了更优的时间复杂度。
无论选择哪种方法,重要的是理解算法背后的原理,并能够灵活运用数据结构。LeetCode 的魅力在于,它不仅是一系列编程题目,更是一场算法思维的盛宴。通过不断地挑战和探索,我们才能真正领悟算法之美。