在O(n log n)时间内对链表进行排序。
解决思路
看到题目中的 nlogn 以及 sort,很自然的联想到mergesort的思想。只不过mergesort通常是以排序数组元素出现的,现在变成了排序链表。
1)找到链表中点 (快慢指针思路,快指针一次走两步,慢指针一次走一步,快指针在链表末尾时,慢指针恰好在链表中点);
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public ListNode sortList(ListNode head) {
if(head==null||head.next==null) return head;
ListNode mid = findMiddle(head);
//跟数组不同,这里只传递头指针
//分成两段,一段的head是head,另一半的head是mid.next
ListNode head1 = sortList(mid.next);
mid.next = null;
ListNode head2 = sortList(head);
//归并排序
return mergeSort(head1,head2);
}
//归并排序
public static ListNode mergeSort(ListNode head1,ListNode head2){
if(head1==null){
return head2;
}
if(head2==null){
return head1;
}
ListNode newhead = new ListNode(0);//new一个链表
ListNode newlist = newhead;//用于记录新链表的head
while(head1!=null && head2!=null){
if(head1.val < head2.val){
newlist.next = head1;
head1 = head1.next;
}
else{
newlist.next = head2;
head2 = head2.next;
}
newlist = newlist.next;
}
if(head1==null){
newlist.next = head2;
}
if(head2==null){
newlist.next = head1;
}
return newhead.next;
}
//寻找链表中点
public static ListNode findMiddle(ListNode head){
ListNode c = head;
ListNode r = head.next;//c与r需要一直间隔两倍,c在1,r在2,c在2,r在4
while(r!=null && r.next!=null){
//当链表长为单数时,r最后一位会跳到null,跳出,c也刚好调到最中间那点
//当链表长为双数时,r会刚好跳到链表末段,跳出,c也刚好跳到双数的中间
c = c.next;
r = r.next.next;
}
return c;
}
}