1、题目描述:
给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
提示:
- 链表中节点的数目在范围 [0, 5 * 104] 内
- -105 <= Node.val <= 105
进阶:你可以在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?
2、解题思路
- 要想在 O(n log n) 时间复杂度和常数级空间复杂度下,需要使用归并排序。
- 这道题需要的前置知识(建议先解决以下LeetCode问题)
- 找出链表的中间节点: 876. 链表的中间结点
- 合并两个有序链表: 21. 合并两个有序链表
- 🤔️什么是归并排序?
假设待排序数组长度为8
a.合并相邻的长度为1的子数组得到排序的长度为2的子数组
b.合并相邻的长度为2的子数组得到排序的长度为4的子数组
c.合并相邻的长度为4的子数组得到排序的长度为8的数组
3、 代码
class Solution {
// 链表一分为二,返回链表的后半段
public ListNode split(ListNode head){
ListNode fast=head;
ListNode slow=head;
while(fast.next!=null&&fast.next.next!=null){
slow=slow.next;
fast=fast.next.next;
}
ListNode second=slow.next;
slow.next=null;
return second;
}
// 合并两个有序链表
public ListNode merge(ListNode head1,ListNode head2){
ListNode dummyHead=new ListNode(0);
ListNode cur=dummyHead;
ListNode ptr1=head1;
ListNode ptr2=head2;
while(ptr1!=null&&ptr2!=null){
if(ptr1.val<=ptr2.val){
cur.next=ptr1;
ptr1=ptr1.next;
}
else{
cur.next=ptr2;
ptr2=ptr2.next;
}
cur=cur.next;
}
cur.next=ptr1!=null?ptr1:ptr2;
return dummyHead.next;
}
// 递归进行归并排序
public ListNode sortList(ListNode head) {
if(head==null||head.next==null){
return head;
}
ListNode head1=head;
ListNode head2=split(head);
head1=sortList(head1);
head2=sortList(head2);
return merge(head1,head2);
}
}