题目
在O(n log n)的时间内使用常数级空间复杂度对链表进行排序。
Sort a linked list in O(n log n) time using constant space complexity.
输入
{3,2,4}
输出
{2,3,4}
思路
若要使得时间复杂度为O(nlogn),常用排序算法有归并算法,但常用归并算法采用了递归的形式,因此此题解法暂时无法满足空间复杂度为常数的条件。
关键点:
1、题干给出的数据结构为链表,注意理清链表中结点的链接变换关系。如node.next=node与node=node.next之间的差异,前者意为将node的指针指向node,后者意为将node指针所指结点作为node结点(node只是一个变量,并不具体定为物理存储上的某一结点)
2、归并排序要求将链表(数组)分为长度相近的两端,需要构造分段函数getMid()
3、本算法钟采用递归的方式,理清递归的流程,合理安排递归顺序。本题中,先将链表分段,分段后需要继续分段,直至分为单个结点或无结点,在进行归并。因此要求形式为
getMid(head){
getMid(head){...}
merge(n1,n2)
}
4、时刻注意分段前、中、后链表的长度问题,确保所有函数都考虑到了链表为空及链表长度为1的特殊情况,避免越界错误。
代码
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* }
*/
public class Solution {
/**
*
* @param head ListNode类
* @return ListNode类
*/
public ListNode sortList (ListNode head) {
// write code here
if(head==null||head.next==null){
return head;
}
ListNode result=getMid(head);
return result;
}
public ListNode getMid(ListNode head){
if(head==null||head.next==null){
return head;
}
ListNode fast;
ListNode slow;
ListNode preEnd;
preEnd=fast=slow=head;
while(fast!=null&&fast.next!=null){
preEnd=slow;
fast=fast.next.next;
slow=slow.next;
}
preEnd.next=null;
ListNode result=merge(getMid(head),getMid(slow));
return result;
}
public ListNode merge(ListNode n1,ListNode n2){
ListNode current=new ListNode(0);
ListNode first=current;
if(n1==null){
current=n2;
}
if(n2==null){
current=n1;
}
while(n1!=null&&n2!=null){
if(n1.val<=n2.val){
current.next=n1;
n1=n1.next;
current=current.next;
} else{
current.next=n2;
n2=n2.next;
current=current.next;
}
}
if(n1!=null){
current.next=n1;
}
if(n2!=null){
current.next=n2;
}
return first.next;
}
}
总结
本题特点在于链表的排序,需要注意链表的特殊性,链接结点语句的复杂性,以及链表分段时保留分段信息的细节。