给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
进阶:
你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
输入:head = [4,2,1,3]
输出:[1,2,3,4]
输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]
示例 3:
输入:head = []
输出:[]
提示:
- 链表中节点的数目在范围 [0, 5 * 104] 内
- -105 <= Node.val <= 105
- 考虑O(n log n) 时间复杂度和O(1)空间复杂度,因此可使用的排序方法为快速排序、堆排序和合并排序;其中合并排序最适合链表。其次,由于递归会开辟额外的栈空间,所以只能使用迭代。
- 采用自底向上的策略,先将链表分成split=1长度的子链表,并两两进行归并排序;在此基础上逐渐增大split(split *= 2),直至split>=length(链表长度)
- 注意:
- 归并时,对于用于归并的两段子链表,若第二段没有,则表明已到链表末尾,可以跳出循环
- 归并时,第一次遍历用于找这次用于归并的两段子链表,可用split控制遍历长度;第二次遍历用于合并两个有序链表,需要计算两段子链表的长度(因为在末尾时,第二段子链表长度不等于split),用这个长度控制遍历长度。
class Solution:
def sortList(self, head: ListNode) -> ListNode:
h = head
length = 0
intv = 1
while h:
h = h.next
length += 1
res = ListNode(None)
res.next = head
# merge the list in different intv.
while intv < length:
pre = res
h = res.next
while h:
# get the two merge head `h1`, `h2`
h1 = h
i = intv
while i and h:
h= h.next
i -= 1
# no need to merge because the `h2` is None.
if i:
break
h2 = h
i = intv
while i and h:
h = h.next
i -= 1
# the `c2`: length of `h2` can be small than the `intv`.
c1 = intv
c2 = intv - i
# merge the `h1` and `h2`.
while c1 and c2:
if h1.val < h2.val:
pre.next = h1
h1 = h1.next
c1 -= 1
else:
pre.next = h2
h2 = h2.next
c2 -= 1
pre = pre.next
pre.next = h1 if c1 else h2
while c1 > 0 or c2 > 0:
pre = pre.next
c1 -= 1
c2 -= 1
pre.next = h
intv *= 2
return res.next