题目

思路
- 一个平淡无奇的解法:遍历链表并且将其存储在arraylist里,然后给arraylist排序,最后创建一个新链表返回…
- 要求 O(n log n) 时间复杂度和常数级空间复杂度。
- 时间复杂度是O(nlogn) 的排序算法包括归并排序、堆排序和快速排序,最适合链表的排序算法是归并排序。
- 如果自顶向下,则要考虑递归实现,此时因为递归会调用栈空间,故自顶向下归并排序的空间复杂度为O(logn)
- 如果要达到 O(1)的空间复杂度,则需要使用自底向上的实现方式
题解思路
自顶向下递归法
- 找到链表的中点,以中点为分界,将链表拆分成两个子链表。(快慢指针)
- 对两个子链表分别排序。
- 将两个排序后的子链表合并,得到完整的排序后的链表。
- 递归的终止条件是链表的节点个数小于或等于1,即当链表为空或者链表只包含1个节点时,不需要对链表进行拆分和排序。
自底向上归并排序
- 首先求得链表的长度length,然后将链表拆分成子链表进行合并。
- 用subLength 表示每次需要排序的子链表的长度,初始时subLength=1。
- 每次将链表拆分成若干个长度为 subLength 的子链表(最后一个子链表的长度可以小于subLength),
- 按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于subLength×2)
- 将subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于length,整个链表排序完毕。
代码(自顶向下递归)
public ListNode sortList(ListNode head) {
return sortList(head,null);
}
public ListNode sortList(ListNode head,ListNode tail){
if(head == null) return head;
if(head.next == tail){
head.next=null;
return head;
}
ListNode slow = head;
ListNode fast = head;
while (fast!=tail){
slow = slow.next;
fast = fast.next;
if(fast!=tail) fast = fast.next;
}
ListNode mid = slow;
ListNode list1 = sortList(head,mid);
ListNode list2 = sortList(mid,tail);
ListNode sorted = merge(list1,list2);
return sorted;
}
public ListNode merge(ListNode head1,ListNode head2){
ListNode dummy = new ListNode();
ListNode temp = dummy;
ListNode temp1 = head1;
ListNode temp2 = head2;
while (temp1!=null && temp2!=null){
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
if (temp1 != null) {
temp.next = temp1;
} else if (temp2 != null) {
temp.next = temp2;
}
return dummy.next;
}
代码(自底向上归并排序)
public ListNode sortList(ListNode head) {
if(head == null) return head;
int length=0;
ListNode node = head;
while (node != null){
length++;
node = node.next;
}
ListNode dummy = new ListNode(0,head);
for(int subLength = 1;subLength<length;subLength*=2){
ListNode pre = dummy;
ListNode cur = dummy.next;
while (cur!=null){
ListNode head1 = cur;
for (int i=1;i<subLength&&cur.next!=null;i++) {
cur = cur.next;
}
ListNode head2 = cur.next;
cur.next=null;
cur = head2;
for (int i=1;i<subLength&&cur!=null && cur.next!=null;i++) {
cur = cur.next;
}
ListNode next = null;
if(cur != null){
next = cur.next;
cur.next=null;
}
ListNode merged = merge(head1, head2);
pre.next = merged;
while (pre.next != null) {
pre = pre.next;
}
cur = next;
}
}
return dummy.next;
}
public ListNode merge(ListNode head1,ListNode head2){
ListNode dummy = new ListNode();
ListNode temp = dummy;
ListNode temp1 = head1;
ListNode temp2 = head2;
while (temp1!=null && temp2!=null){
if (temp1.val <= temp2.val) {
temp.next = temp1;
temp1 = temp1.next;
} else {
temp.next = temp2;
temp2 = temp2.next;
}
temp = temp.next;
}
if (temp1 != null) {
temp.next = temp1;
} else if (temp2 != null) {
temp.next = temp2;
}
return dummy.next;
}