力扣第 148 题 - 轻松排序链表,1800 字详解
2023-12-19 09:05:39
力扣第 148 题 - 排序链表
问题陈述:
给你链表的头结点 head
,请将其按 升序
排列并返回 排序后的链表。
示例 1:
输入:head = [4,2,1,3]
输出:[1,2,3,4]
示例 2:
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
解法一:归并排序
归并排序是一种经典的排序算法,它将链表分成多个子链表,对每个子链表进行排序,然后将排序后的子链表合并为一个排序后的链表。
-
分解: 将链表分成两个子链表。如果链表长度为奇数,则将中间节点作为第一个子链表的尾节点,将剩余节点作为第二个子链表。如果链表长度为偶数,则将中间两个节点作为第一个子链表的尾节点,将剩余节点作为第二个子链表。
-
征服: 对每个子链表递归应用归并排序。
-
合并: 将排序后的子链表合并为一个排序后的链表。可以使用两个指针来合并子链表,一个指针指向第一个子链表的头部,另一个指针指向第二个子链表的头部。将较小的节点添加到合并后的链表中,并更新指针指向下一个节点。
def merge_sort(head):
if not head or not head.next:
return head
# 将链表分成两个子链表
slow, fast = head, head.next
while fast and fast.next:
slow = slow.next
fast = fast.next.next
mid = slow.next
slow.next = None
# 递归对子链表进行归并排序
left = merge_sort(head)
right = merge_sort(mid)
# 合并两个排序后的子链表
return merge(left, right)
def merge(left, right):
dummy = ListNode()
curr = dummy
while left and right:
if left.val < right.val:
curr.next = left
left = left.next
else:
curr.next = right
right = right.next
curr = curr.next
curr.next = left or right
return dummy.next
解法二:快速排序
快速排序是一种经典的排序算法,它选择一个基准节点,将链表分成两个子链表,一个子链表包含所有小于基准节点的节点,另一个子链表包含所有大于基准节点的节点。然后对两个子链表递归应用快速排序,直到所有子链表都排序完成。
-
选择基准节点: 选择链表的中间节点作为基准节点。如果链表长度为奇数,则将中间节点作为基准节点。如果链表长度为偶数,则将中间两个节点的平均值作为基准节点。
-
分区: 将链表分成两个子链表,一个子链表包含所有小于基准节点的节点,另一个子链表包含所有大于基准节点的节点。可以使用两个指针来分区链表,一个指针指向基准节点,另一个指针指向链表的头部。将较小的节点添加到左子链表中,将较大的节点添加到右子链表中。
-
递归: 对两个子链表递归应用快速排序。
def quick_sort(head):
if not head or not head.next:
return head
# 选择基准节点
pivot = head.val
# 将链表分成两个子链表
left, right = ListNode(), ListNode()
left_curr, right_curr = left, right
curr = head.next
while curr:
if curr.val < pivot:
left_curr.next = curr
left_curr = left_curr.next
else:
right_curr.next = curr
right_curr = right_curr.next
curr = curr.next
left_curr.next = None
right_curr.next = None
# 递归对子链表进行快速排序
left = quick_sort(left.next)
right = quick_sort(right.next)
# 合并两个排序后的子链表
head.next = left
curr = head
while curr.next:
curr = curr.next
curr.next = right
return head
性能分析
归并排序和快速排序都是经典的排序算法,它们的平均时间复杂度都是 O(n log n),其中 n 是链表的长度。然而,快速排序的最好情况时间复杂度是 O(n),最坏情况时间复杂度是 O(n^2),而归并排序的最好情况和最坏情况时间复杂度都是 O(n log n)。
在实践中,快速排序通常比归并排序更快,因为快速排序不需要额外的空间来合并子链表。然而,如果链表已经接近有序,那么归并排序可能比快速排序更快。