题目:
Sort a linked list in O(n log n) time using constant space complexity.
思路:O(nlogn)的sort有quick sort, merge sort, heap sort. 首先排除heap sort, heap需要用到O(n)的空间。其次排除quick sort, quick sort需要大量的swap,同时还需要一个指针从后向前移动,单链表不支持这些。事实上,链表排序最好的方法就是merge sort,因为链表很好的克服了merge sort需要额外空间这一缺点。具体做法是递归分解链表,在返回的时候对两个子链表进行合并。
class Solution {
public:
ListNode *sortList(ListNode *head) {
if (head == nullptr || head->next == nullptr) return head; //reach the end
ListNode* fast = head;
ListNode* slow = head;
while (fast->next != nullptr && fast->next->next != nullptr) {
fast = fast->next->next;
slow = slow->next;
}
ListNode* mid = slow->next;
slow->next = nullptr; //break the list
ListNode* l1 = sortList(head);
ListNode* l2 = sortList(mid);
// merge the two sorted sublist
ListNode dummy(0);
ListNode* runner = &dummy;
while (l1 != nullptr || l2 != nullptr) {
if (l1 == nullptr) { //l1 is empty
runner->next = l2;
l2 = l2->next;
} else if (l2 == nullptr) { //l2 is empty
runner->next = l1;
l1 = l1->next;
} else {
if (l1->val < l2->val) { //choose l1
runner->next = l1;
l1 = l1->next;
} else { //choose l2
runner->next = l2;
l2 = l2->next;
}
}
runner = runner->next;
}
return dummy.next;
}
};
总结:递归实际上是生成了一个二叉树,树的根为长度n的链表,第二层为两个n/2的链表,第三层为4个n/4的链表 ... 在merge的时候,每一层都要touch n个节点,因此每一层的复杂度为O(n). 一共有logn层,所以复杂度为O(nlogn).