和刚刚做的题目一样,但是刚刚的147题是用插入排序罢了,但是这个题目,我们为了追求更快的速度,采用了归并排序的方法。这里为什么用归并排序呢,因为它的时间复杂度是O(nlogn),而其他常见的排序,比如快速排序,它的最坏情况是O(n2),不一定有归并排序快,而且它的partition还有点复杂,另外的堆排序也比较麻烦,因为leetcode题库里面他的链表数据就只有几个,用堆排序的空间复杂度比较大,因为它的空间复杂度,可能过不了审,所以也不采取堆排序的方法,然而其他常见的排序方法的时间复杂度基本上到了O(n2),所以这里我们采用归并排序的思想来实现这个题目,而且一般的小规模的排序问题一般都采用归并排序来实现。
归并排序本身是一种分治法的思想,将一个问题拆解成为子问题去解决,然后子问题的介又合并为原本问题的解。本题中,子问题通过递归来求解,代码第一行就是递归的出口。然后通过快慢指针来将原本的链表拆解成两个子链表,分别对子链表来排序,然后将子链表合并即可实现链表的排序。
public class t148 {
public ListNode sortList(ListNode head) {
if(head==null||head.next==null) return head;
ListNode f=head.next;
ListNode s=head;
while(f!=null&&f.next!=null){//快慢指针求之间位置
s=s.next;
f=f.next.next;
}
ListNode newhead=s.next;//拆分
s.next=null;
ListNode left=sortList(head);
ListNode right=sortList(newhead);
ListNode ret=new ListNode(0);//合并之后保存结果的链表
ListNode temp=ret;
while(right!=null&&left!=null){//比较并连接,注意这里没有创建新的节点。
if(right.val<left.val){
temp.next=right;
right=right.next;
}else{
temp.next=left;
left=left.next;
}
temp=temp.next;
}
temp.next=(right==null?left:right);//三目运算符将后面没有比较的直接接上去
return ret.next;
}
}