题目要求:
在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。
分析:
对于时间复杂度为O(nlogn)的排序,对于数组来说通常使用快速排序归并排序等,这里是链表,每个节点有自己节点的值并且每个节点都有指向下一个节点的指针。
使用归并排序使用分治法的思想,先将链表二分为两个链表左边一个链表右边成为一个链表,左右分别排序然后进行合并。
问题:如何从中间将链表均分?如何合并链表?
答案是:1.链表的均分使用两个指针,一个快指针一个满指针,快指针每次向前走两步,慢指针每次向前走一步,两个指针同时向前进行,当快指针走到链表结尾时,慢指针指向的位置就是中间节点。
2.合并:开辟新的链表,比较左右两边的大小,将较小的节点放在开辟的新位置,然后节点一次向后推进。
代码如下:
```java
public class Solution {
public ListNode sortList(ListNode head) {
if(headnull||head.nextnull){
return head;
}
//取链表中间的节点
ListNode mid=midList(head);
//递归进行左右继续划分
ListNode right=sortList(mid.next);
mid.next=null;
ListNode left=sortList(head);
//合并
return MergerList(left,right);
}
public ListNode midList(ListNode phead){
if(pheadnull){
return null;
}
ListNode snowNode=phead;//慢指针一次走一步
ListNode fastNode=snowNode.next;//快指针一次走两步
while(fastNode!=null&&fastNode.next!=null){
snowNode=snowNode.next;
fastNode=fastNode.next.next;
}
return snowNode;
}
public ListNode MergerList(ListNode left,ListNode right){
if(leftnull){
return right;
}
if(right==null){
return left;
}
ListNode tmpList=new ListNode(0);
ListNode p=tmpList;
while(left!=null&&right!=null){
if(left.val>=right.val){
p.next=right;
right=right.next;
}else{
p.next=left;
left=left.next;
}
p=p.next;
}
if(left!=null){
p.next=left;
}
if(right!=null){
p.next=right;
}
return tmpList.next;
}
}