题目的意思很简单:将一个链表以O(nlogn)的时间复杂度排好序,并且使用常数空间。
关于排序算法的选择:这里我犯了个错误,就是将快速排序的时间复杂度记成了O(nlogn)。。。。(由于对快速排序比较熟悉-,-!)。但是实际情况是如果主元选择不当,最坏的情况会达到O(n2)。而且LeetCode上好像也特意针对快排做了测试用例,所以用快排会TLE。所以要使用归并排序,这种算法性能比较稳定,都是O(nlogn)。
这里做一个补充:虽然归并排序性能比较稳定,但是查资料可知,最常用的还是快排,归并排序的话,需要一定的辅助空间。对于快排,如果随机选择主元的话,快排的最坏情况出现的概率会随数据增多而大大减小,所以一般使用快排。
这里贴出我的代码(包含了快排和归并排序)---------------------(俩算法写了一晚上,想想没脸见人了。。。。)
关于归并的思想是记录本次要排序的链表长度,然后如果长度小于3,就合并,否则就递归排序,之后再合并。注意的地方是一定要先排序右边的链表,这样才能保证preHead的正确性。
/** * 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) { ListNode fakeHead = new ListNode(Integer.MIN_VALUE);//To avoid null of the preHead fakeHead.next = head; ListNode p = head; int n = 0; while(p != null){ n++; p = p.next; } return mergeSort(fakeHead , head , n); } public ListNode mergeSort(ListNode preHead , ListNode head , int len){ //如果len为1,2,那么归并为一个list,返回两个list的新head if(len == 1){ return head; } if(len == 2){ if(head.val > head.next.val){ ListNode temp = head.next.next; preHead.next = head.next; preHead.next.next = head; head.next = temp; } return preHead.next; } //对两个list进行mergeSort int newLen1 = len / 2; int newLen2 = len - newLen1; ListNode p = head; for(int i = 1 ; i < newLen1 ; i++) { p = p.next; } //Must in the sequence of right----left ListNode newHead2 = mergeSort(p,p.next,newLen2); ListNode newHead1 = mergeSort(preHead,head,newLen1); //Merge ListNode newHead = null; if(newHead1.val < newHead2.val){ newHead = newHead1; newHead1 = newHead1.next; newLen1--; }else{ newHead = newHead2; newHead2 = newHead2.next; newLen2--; } preHead.next = newHead; while(newLen1 > 0 && newLen2 > 0){ if(newHead1.val < newHead2.val){ newHead.next = newHead1; newHead1 = newHead1.next; newHead = newHead.next; newLen1--; }else{ newHead.next = newHead2; newHead2 = newHead2.next; newHead = newHead.next; newLen2--; } } if(newLen1 == 0){ newHead.next = newHead2; } if(newLen2 == 0){ newHead.next = newHead1; newLen1--; //newHead1 = newHead1.next; while(newLen1 >= 1){ newHead1 = newHead1.next; newLen1--; } newHead1.next = newHead2; } return preHead.next; } public ListNode quickSort(ListNode head ,ListNode start ,ListNode end){ if(head ==end || head.next == end) return head; //choose the first one ListNode nHead = head; ListNode previous = head; ListNode p = head.next; ListNode npivot = head; while(true){ if(p == end){ break; } if(p.val <= npivot.val){ ListNode temp = p.next; previous.next = temp; p.next = nHead; //npivot.next = temp; if(start != null) start.next = p; nHead = p; p = temp; }else{ previous = p; p = p.next; } } if(start == null) nHead = quickSort(nHead , start , npivot); else { quickSort(nHead, start, npivot); } quickSort(npivot.next , npivot , end); return nHead; } /////////////////////////////////////////////////// ////////////////////TEST////////////////////////// public static void main(String[] args){ Solution obj = new Solution(); ListNode h = obj.create(new int[]{7,5,4,6,3,2,1}); print(h); h = obj.sortList(h); print(h); } public ListNode create(int[] array){ ListNode temp = new ListNode(array[0]); ListNode head = temp; for(int i = 1 ; i < array.length ; i++){ ListNode t = new ListNode(array[i]); temp.next = t; temp = t; } return head; } public static void print(ListNode head){ ListNode p = head; while(p != null){ System.out.println(p.val); p = p.next; } } } class ListNode{ int val; ListNode next; public ListNode(int val){ this.val = val; next = null; } }