原题链接:#148 Sort List
要求:
给一个单向链表排序,要求时间复杂度为O(nlogn)且空间复杂度为O(1)。
单向链表定义如下:
class ListNode{
int val;
ListNode next;
ListNode(int x){
this.val = x;
}
}
难度:中等
分析:
若没有时间复杂度及空间复杂度的限制,解法将会很多。譬如先遍历一遍链表,将其所有元素放在一个数组内,以任一种排序算法排序后重新生成单向链表,比如最简单的冒泡。这种思路并非不可取,毕竟出于解决问题的角度它体现了一种转化的思想,把链表操作转化为数组操作并用开发人员自己最熟悉且用起来最舒服的算法排序并能切实解决问题,并不能全盘否定。这种解决方案的时间复杂度为O(n2),空间复杂度为O(n)。
题目加上了时间和空间两方面的限制,就要求我们优化一下算法了。同时,既然参数是链表,要求返回值也是链表,实在没有必要使用其他的数据结构来回转换。既满足时间复杂度要求又不需要O(n)辅助数据结构的,考虑采用归并排序算法。
各种排序算法的时间复杂度和空间复杂度比较:
图片来自:vincent-cws
解决方案:
Java - 384ms
public ListNode sortList(ListNode head) {
if(head==null||head.next==null){
return head;
}
int nodeSum = 0;
ListNode tmp = head;
while(tmp!=null){
tmp = tmp.next;
nodeSum++;
}
tmp = head;
for(int i=1; i<nodeSum/2; i++){
tmp=tmp.next;
}
ListNode l1 = head; //将原链表分拆为两个子链表,分别排序然后合并
ListNode l2 = tmp.next;
tmp.next=null;
ListNode result = merge(sortList(l1), sortList(l2));
return result;
}
public ListNode merge(ListNode l1, ListNode l2){
ListNode head = new ListNode(0);
ListNode cursor = head;
while(l1!=null&&l2!=null){
if(l1.val<l2.val){
cursor.next=l1;
l1 = l1.next;
}else{
cursor.next=l2;
l2=l2.next;
}
cursor = cursor.next;
}
if(l1!=null){
cursor.next = l1;
}else {
cursor.next = l2;
}
return head.next;
}