Sort a linked list in O(n log n) time using constant space complexity.
----------------------------------------------------------------------------------------------------------------------------------------
这里,依旧利用分治的思想,更具体点就是归并排序的算法。
假设list 的前一半已经排好序的,后一半也已经排好序了,那么将这2 Merge起来(如果不知道怎么Merge,可以看我前面的博文)
那么具体list的前一半怎么排序呢?也是拆分成2部分。
现在我们需要解决的问题,如何将得到list的中间节点呢?不像数组有index,可以直接得到。
这里,又是two pointer,双指针了,一个slow指针一次走1步,一个fast指针一次走2步。
那么当fast碰到null的时候,slow就在中间部位了。
1. 我们先对后面的 slow.next 进行递归排序,得到L2。
2. 接着,我们将slow.next = null, 即从中间将原链表断开。
3.对前面部分进行递归排序,得到L1。
4. 最后将L1和L2 merge。
时间复杂度:O( n log n )
空间复杂度:O ( 1 )
运行时间:
代码:
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode fast = head.next, slow = head;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
}
ListNode l2 = sortList(slow.next);
slow.next = null;
ListNode l1 = sortList(head);
return mergeTwoLists(l1, l2);
}
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode fakeNode = new ListNode(-1), cur = fakeNode, curl1 = l1, curl2 = l2;
while (curl1 != null && curl2 != null) {
if (curl1.val < curl2.val) {
cur.next = curl1;
curl1 = curl1.next;
} else {
cur.next = curl2;
curl2 = curl2.next;
}
cur = cur.next;
}
cur.next = curl1 != null ? curl1 : curl2;
return fakeNode.next;
}