Skip to main content

148.排序链表

标签: linked-list, sort, divide-and-conquer

难度: Medium

通过率: 60.23%

原题链接: https://leetcode.com/problems/sort-list/description/

题目描述

给定一个链表的头节点,将链表中的节点按升序排序后返回。

解题思路

解决排序链表问题的有效方法是使用归并排序。这主要因为归并排序的时间复杂度为 O(nlogn)O(n \log n),符合题目对于时间复杂度的要求。虽然在链表中实现归并排序通常会使用 O(logn)O(\log n) 的递归栈空间,但也可以通过更复杂的操作来实现 O(1)O(1) 的空间复杂度。具体思路如下:

  1. 拆分:通过快慢指针方法,将当前链表拆分成两个子链表。

    • 使用两指针 slowfastslow每次移动一步,fast每次移动两步。fast到达链表末尾时,slow就在中点。
    • 将链表断开,形成两个独立的子链表。
  2. 递归排序:对拆分出来的两个子链表分别进行排序。

    • 递归调用排序函数,对两个子链表分别排序。
  3. 合并两个已排序的子链表

    • 使用合并两个有序链表的方法,将两个子链表合并成一个有序链表。
    • 创建一个哨兵节点用于简化合并过程。

这样递归拆分和合并,直到所有子链表长度为1,最终完成了排序。

代码实现

class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next

class Solution:
def sortList(self, head: ListNode) -> ListNode:
# 定义merge函数用于合并两个有序链表
def merge(l1, l2):
dummy = tail = ListNode(0) # 创建哑节点
while l1 and l2:
if l1.val < l2.val:
tail.next, l1 = l1, l1.next
else:
tail.next, l2 = l2, l2.next
tail = tail.next
tail.next = l1 or l2
return dummy.next

# 基本情况
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 = self.sortList(head)
right = self.sortList(mid)

# 合并已排序链表
return merge(left, right)

复杂度分析

时间复杂度:O(nlogn)O(n \log n),每次组合操作时间为 O(n)O(n),且递归深度为 O(logn)O(\log n)

空间复杂度:O(logn)O(\log n),由于递归的栈空间。