给你链表的头结点 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 = \[\]
输出:\[\]
提示:
- 链表中节点的数目在范围
[0, 5 * 104]内 -105 <= Node.val <= 105
进阶: 你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
方法一:归并排序(递归)
1.找到链表中间节点 head2 的前一个节点,并断开 head2 与其前一个节点的连接,这样链表就被分成了两段更短的链表,再对这两段链表递归调用 sortList. 得到排好序后的 head 和 head2 ,再合并两个有序链表
找中间节点显然使用快慢指针,合并两个有序链表使用双指针
java
class Solution {
public ListNode sortList(ListNode head) {
if(head == null || head.next == null) {
return head;
}
// 找中间节点
ListNode head2 = findMidNode(head);
//分治
head = sortList(head);
head2 = sortList(head2);
//合并
return mergeTwoList(head, head2);
}
// 快慢指针找链表的中间节点
public ListNode findMidNode(ListNode head) {
ListNode pre = head; // 记录 slow 的前一个节点,方便后续断开
ListNode slow = head;
ListNode fast = head;
while(fast != null && fast.next != null) {
pre = slow;
slow = slow.next;
fast = fast.next.next;
}
pre.next = null; // 断开
return slow; // 返回后半部分,因为前半部分的头节点已经知道是 head 了
}
// 双指针合并两个链表
public ListNode mergeTwoList(ListNode head1, ListNode head2) {
ListNode dummy = new ListNode();
ListNode cur = dummy; // cur 指向新链表的末尾
while(head1 != null && head2 != null) {
if(head1.val < head2.val) {
cur.next = head1;
head1 = head1.next;
} else {
cur.next = head2;
head2 = head2.next;
}
cur = cur.next;
}
cur.next = head1 != null ? head1 : head2; // 拼接剩余链表
return dummy.next;
}
}
递归深度为 O(logn),所以空间复杂度为 O(logn)
由于每层链表长度之和为 O(n),所以时间复杂度为 O(nlogn)
方法二:归并排序(迭代)
把方法一中的递归过程反向用迭代处理,省去递归的栈开销
递归方法中,我们是将链表分割为2份、4份、8份...直到每一份只有一个节点,再进行合并。现在我们自底向上处理:
1.归并长度为1的子链表:把第一个节点和第二个节点归并,放到链表末尾,再归并第三个节点和第四个节点,放到链表末尾......直到全部遍历完毕(因此需要事先直到链表长度),现在两两节点之间是有序的
2.归并长度为2的子链表:把第一组节点和第二组节点归并(每组两个节点),放到链表末尾,再归并第三组节点和第四组节点,放到链表末尾......直到全部遍历完毕,现在每四个节点之间是有序的
3.归并的子链表的长度是首项为1,公比为2的等比数列
4.直到归并的子链表的长度不小于链表长度
python
class Solution:
# 获取链表长度
def getListLength(self, head : Optional[ListNode]) -> int :
length = 0
while head :
length += 1
head = head.next
return length
# 分割链表
def splitList(self, head : Optional[ListNode], size : int) -> Optional[ListNode] :
# 尝试找到下一组节点的头节点的前一个节点
cur = head
for _ in range(size - 1) : # 循环 size - 1 次,最终 cur 指向第 size 个节点(如果有)
if cur is None :
break
cur = cur.next
# 如果链表长度 <= size
if cur is None or cur.next is None :
return None # 不需要分割
next_head = cur.next
cur.next = None # 断开组与组之间的连接
return next_head # 返回下一组的头节点,因为当前组的头节点已经知道是 head 了
# 双指针合并两个有序链表,因为自底向上,所以要返回合并后链表的头节点和尾节点
def mergeTwoLists(self, list1 : Optional[ListNode], list2 : Optional[ListNode]) -> Optional[ListNode] :
cur = dummy = ListNode() # 哨兵 dummy, cur 指向新链表的尾节点
while list1 and list2 :
if list1.val < list2.val :
cur.next = list1
list1 = list1.next
else :
cur.next = list2
list2 = list2.next
cur = cur.next
cur.next = list1 or list2 # 拼接剩余链表
# 得到尾节点
while cur.next :
cur = cur.next
return dummy.next, cur
def sortList(self, head: Optional[ListNode]) -> Optional[ListNode] :
length = self.getListLength(head)
dummy = ListNode(next = head) # 因为头节点可能变化,所以用虚拟头节点简化逻辑
step = 1 # 归并的链表的长度
while step < length :
cur = dummy.next # 每轮循环的起始节点
list_tail = dummy # 新链表的末尾
while cur :
# 从 cur 开始,分割出两段长为 step 的链表,归并后扔到链表末尾
head1 = cur
head2 = self.splitList(head1, step)
cur = self.splitList(head2, step) # 下一轮循环的起始节点
# 合并两段长为 step 的链表
head, tail = self.mergeTwoLists(head1, head2)
# 将合并后的头节点 head 放到当前链表尾节点的后面
list_tail.next = head
list_tail = tail # 现在 tail 是整个链表的末尾
step *= 2
return dummy.next