一、题目描述:
在 O ( n l o g n ) O(n log n) O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
二、解题思路 & 代码
2.1 类似快排
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
# 快速排序
if not head: return None
# 分成三个链表,分别是比轴心数小,相等,大的数组成的链表
# small equal large 的缩写
# 都指向相应链表的 head
s = e = l = None
target = head.val
while head:
nxt = head.next
if head.val>target:
head.next = l
l = head
elif head.val==target:
head.next = e
e = head
else:
head.next = s
s = head
head = nxt
# 拆完各自排序即可,equal 无需排序
s = self.sortList(s)
l = self.sortList(l)
# 合并 3 个链表, 这一步复杂度是 o(n)
# # 可以同时返回链表的头指针和尾指针加速链表的合并。
dummy = ListNode(0)
cur = dummy # cur: 非 None 的尾节点
# p: 下一个需要连接的节点
for p in [s, e, l]:
while p:
cur.next = p
p = p.next
cur = cur.next
return dummy.next
要注意的是,快速排序的最坏时间复杂度是 o ( n 2 ) o(n^{2}) o(n2) ,均摊复杂度才是 o ( n l o g n ) o(nlogn) o(nlogn)。除非用 b f p r t bfprt bfprt 等算法先进行轴心数选择,才可以降低最坏时间复杂度。
参考:
2.2 归并排序(递归法)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
if not head or not head.next: return head # termination.
# cut the LinkedList at the mid index.
slow, fast = head, head.next
while fast and fast.next:
fast, slow = fast.next.next, slow.next
mid, slow.next = slow.next, None # save and cut.
# recursive for cutting.
left, right = self.sortList(head), self.sortList(mid)
# merge `left` and `right` linked list and return it.
h = res = ListNode(0)
while left and right:
if left.val < right.val:
h.next, left = left, left.next
else:
h.next, right = right, right.next
h = h.next
h.next = left if left else right
return res.next
2.3 归并排序(从底至顶直接合并)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def sortList(self, head: ListNode) -> ListNode:
h, length, intv = head, 0, 1
while h: h, length = h.next, length + 1
res = ListNode(0)
res.next = head
# merge the list in different intv.
while intv < length:
pre, h = res, res.next
while h:
# get the two merge head `h1`, `h2`
h1, i = h, intv
while i and h:
h, i = h.next, i - 1
if i:
break # no need to merge because the `h2` is None.
h2, i = h, intv
while i and h:
h, i = h.next, i - 1
c1, c2 = intv, intv - i # the `c2`: length of `h2` can be small than the `intv`.
# merge the `h1` and `h2`.
while c1 and c2:
if h1.val < h2.val:
pre.next, h1, c1 = h1, h1.next, c1 - 1
else:
pre.next, h2, c2 = h2, h2.next, c2 - 1
pre = pre.next
pre.next = h1 if c1 else h2
while c1 > 0 or c2 > 0:
pre, c1, c2 = pre.next, c1 - 1, c2 - 1
pre.next = h
intv *= 2
return res.next