Sort a linked list in O(n log n) time using constant space complexity.
这道题是Linked List的排序,但是对空间复杂度是有要求的。
我首先把昨天学会的那个插入排序写上了,本来以为不会通过,没想到竟然通过了。但是这个用时竟然有603ms,很吓人。
class Solution {
public ListNode sortList(ListNode head) {
if(head == null) return head;
ListNode helper = new ListNode(0);
ListNode cur = head;
ListNode pre = helper;
ListNode next = null;
while(cur != null) {
next = cur.next;
while(pre.next != null && pre.next.val < cur.val) {
pre = pre.next;
}
cur.next = pre.next;
pre.next = cur;
pre = helper;
cur = next;
}
return helper.next;
}
}
然后我看了discuss,发现了点赞最多的一个回答。这个方法,用了分而治之和递归的思想,很多人说由于用了递归不满足空间复杂度的要求。
class Solution {
public ListNode sortList(ListNode head) {
if (head == null || head.next == null)
return head;
// step 1. cut the list to two halves
ListNode prev = null, slow = head, fast = head;
while (fast != null && fast.next != null) {
prev = slow;
slow = slow.next;
fast = fast.next.next;
}
prev.next = null;
// step 2. sort each half
ListNode l1 = sortList(head);
ListNode l2 = sortList(slow);
// step 3. merge l1 and l2
return merge(l1, l2);
}
ListNode merge(ListNode l1, ListNode l2) {
ListNode l = new ListNode(0), p = l;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
p.next = l1;
l1 = l1.next;
} else {
p.next = l2;
l2 = l2.next;
}
p = p.next;
}
if (l1 != null)
p.next = l1;
if (l2 != null)
p.next = l2;
return l.next;
}
}
还看到了一种解法,这个是空间复杂度为O(1)的。
class Solution {
public ListNode sortList(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode [] list = new ListNode[2];
boolean done = (null == head);
// Keep partitioning our list into bigger sublists length. Starting with a size of 1 and doubling each time
for (int step = 1; !done; step *= 2) {
done = true;
ListNode prev = dummy;
ListNode remaining = prev.next;
do {
// Split off two sublists of size step
for (int i = 0; i < 2; ++i) {
list[i] = remaining;
ListNode tail = null;
for (int j = 0; j < step && null != remaining; ++j, remaining = remaining.next) {
tail = remaining;
}
// Terminate our sublist
if (null != tail) {
tail.next = null;
}
}
// We're done if these are the first two sublists in this pass and they
// encompass the entire primary list
done &= (null == remaining);
// If we have two sublists, merge them into one
if (null != list[1]) {
while (null != list[0] || null != list[1]) {
int idx = (null == list[1] || null != list[0] && list[0].val <= list[1].val) ? 0 : 1;
prev.next = list[idx];
list[idx] = list[idx].next;
prev = prev.next;
}
// Terminate our new sublist
prev.next = null;
} else {
// Only a single sublist, no need to merge, just attach to the end
prev.next = list[0];
}
} while (null != remaining);
}
return dummy.next;
}
}