题目
题解
自己用数组存,直接sort,过了,但是不符合他的要求空间复杂度O(1),下面是官方题解给出的两个方法。
归并排序
综合考虑时间复杂度为 O(nlogn) 的排序算法(归并、堆和快排),归并排序是最适合链表的。
首先来复习一下数组实现的归并排序:
再来看下在链表上怎么实现归并排序,有以下两种方式,它们空间复杂度不同:
递归版归并排序
对链表自顶向下归并排序的过程如下。
-
找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法。
-
对两个子链表分别排序。
-
将两个排序后的子链表合并,得到完整的排序后的链表。可以使用「21. 合并两个有序链表」的做法,将两个有序的子链表进行合并。
class Solution {
public ListNode sortList(ListNode head) {
if(head==null||head.next==null)//只剩一个结点时直接返回
return head;
//找中点
ListNode fast=head.next,slow=head;
while(fast!=null&&fast.next!=null){
slow=slow.next;
fast=fast.next.next;
}
ListNode half=slow.next;
slow.next=null;//断链
//两部分分别排序
ListNode list1=sortList(head);
ListNode list2=sortList(half);
//归并
ListNode dummyHead=new ListNode(0);
ListNode p=dummyHead;
while(list1!=null&&list2!=null){
if(list1.val<list2.val){
p.next=list1;
list1=list1.next;
}
else{
p.next=list2;
list2=list2.next;
}
p=p.next;
}
p.next=list1==null?list2:list1;
return dummyHead.next;
}
}
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度: O ( l o g n ) O(logn) O(logn),递归所需空间
迭代版归并排序
使用自底向上的方法实现归并排序,则可以达到 O(1) 的空间复杂度。
首先求得链表的长度 length,然后将链表拆分成子链表进行合并。
具体做法如下。
-
用 subLength 表示每次需要排序的子链表的长度,初始时 subLength=1。
-
每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于 subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。合并两个子链表仍然使用「21. 合并两个有序链表」的做法。
-
将 subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于 length,整个链表排序完毕。
注意:截取完一定记得断链啊断链! 这回又忘记了,导致链表成了一个环,时间超限
class Solution {
public ListNode sortList(ListNode head) {
if(head==null)//只剩一个结点时直接返回
return head;
//计算链表长度
int length=0;
ListNode p=head;
while(p!=null){
length++;
p=p.next;
}
//迭代归并排序
ListNode dummyHead=new ListNode(0,head);
for(int sublength=1;sublength<length;sublength<<=1){
ListNode pre=dummyHead;
p=dummyHead.next;
while(p!=null){
ListNode h1=p;
for(int i=0;i<sublength-1&&p.next!=null;i++)
p=p.next;
ListNode h2=p.next;
p.next=null;
p=h2;
for(int i=0;i<sublength-1&&p!=null&&p.next!=null;i++)//加上p!=null,防止h2是空
p=p.next;
//记录p.next,供下一轮开始
if(p!=null){
ListNode nextRoundStart=p.next;
p.next=null;//断链
p=nextRoundStart;
}
//归并
ListNode merged=merge(h1,h2);
pre.next=merged;
while(pre.next!=null)
pre=pre.next;
}
}
return dummyHead.next;
}
//归并
public ListNode merge(ListNode head1,ListNode head2){
ListNode dummyHead=new ListNode(0);
ListNode p=dummyHead,list1=head1,list2=head2;
while(list1!=null&&list2!=null){
if(list1.val<list2.val){
p.next=list1;
list1=list1.next;
}
else{
p.next=list2;
list2=list2.next;
}
p=p.next;
}
p.next=list1==null?list2:list1;
return dummyHead.next;
}
}
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)
空间复杂度: O ( 1 ) O(1) O(1)