在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3
输出: 1->2->3->4
示例 2:
输入: -1->5->3->4->0
输出: -1->0->3->4->5
题目要求时间复杂度为O(nlogn),我们考虑使用排序中的归并排序,归并排序有两种排序方法。
第一种是递归形式的归并排序,但是这种方法需要递归操作,所以空间复杂度为O(logn),与题目不符;归并排序的另一种形式为迭代形式,迭代形式不需要进行递归,同时可以根据指向改变链表的拼接顺序,所以只需要常数级的空间就可以完成任务,所以我们使用迭代形式的归并算法进行编程。
class Solution:
def sortList(self, head: ListNode) -> ListNode:
h = head
length = 0 # 保存链表长度
intv = 1 # 用于选择将intv的两个链表进行合并
while h: # 计算链表长度
h = h.next
length = length + 1
res = ListNode(0) # 伪头部
res.next = head # 伪头部后拼接真头部
while intv < length:
pre = res # 初始为伪头部
h = res.next # 初始为head
while h:
h1 = h
i = intv
while i and h: # 选择intv长度的一段链表
h = h.next
i = i - 1
if i:
break
h2 = h
i = intv
while i and h: # 选择intv长度的另一段链表
h = h.next
i = i - 1
c1, c2 = intv, intv - i # 因为第二段链表的长度可能不够intv,所以需要进行判断i是否为零,如果不为零则需要减去
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: # 需要找到新的拼接的链表起点,判断c1或者c2大于0时则需要将链表头节点进行后移
pre, c1, c2 = pre.next, c1 - 1, c2 - 1
pre.next = h
intv *= 2 # 迭代长度乘于2
return res.next
空间复杂度为O(nlogn),时间复杂度为O(1)。