Sort List
Sort a linked list in O(n log n) time using constant space complexity.
tag: list, sort
9/22/2015 update
a cleaner solution
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode* sortList(ListNode* head) {
//base condition
if(head == NULL || head->next == NULL) return head;
ListNode * mid = splitList(head);
mid = sortList(mid);
head = sortList(head);
//merge two sorted list
ListNode dummyHead = ListNode(0);
ListNode *tail = &dummyHead;
while(mid != NULL && head != NULL){
ListNode * &p = mid->val < head->val? mid: head;
tail->next = p;
tail = tail->next;
p = p->next;
}
tail->next = mid == NULL? head: mid;
return dummyHead.next;
}
//split the list evenly
ListNode * splitList(ListNode * head){
ListNode * fast, * slow, * prev;
fast = slow = head;
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
prev = slow;
slow = slow->next;
}
prev->next = NULL;
return slow;
}
};
想到了归并排序(merge sort),但是在犹豫寻找list的中点的额外开销。因为数组的话可以直接利用下标(start + end) / 2来获取中点,list的话必须用N/2的时间遍历到中点。怕这样的时间开销会让最终的结果超过o(nlogn)。
实际是我多虑了。
对于 T(N) = 2T(N/2) + N 的递推式,最终的时间开销是o(nlogn)
在本题中, T(N) = 2T(N/2) + N/2 + N。最终的时间开销也是o(nlogn),在一个量级上。
找到List的中点,可以用fast-slow指针法。定义两个指针,一个指针每次走两步,另一个指针每次走一步。这样当快指针走到结尾时,慢指针正好走到中间。
然后对于分成两半的list,先sort,再merge。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *sortList(ListNode *head) {
if(head == NULL || head->next == NULL){
return head;
}
else{
ListNode * fast, * slow, * prev;
fast = slow = head;
//split list into two parts
while(fast != NULL && fast->next != NULL){
fast = fast->next->next;
prev = slow;
slow = slow->next;
}
prev->next = NULL;
ListNode * leftPart = head;
ListNode * rightPart = slow;
ListNode * sortedLeftPart = sortList(leftPart);
ListNode * sortedRightPart = sortList(rightPart);
return merge(sortedLeftPart, sortedRightPart);
}
}
ListNode * merge(ListNode * left, ListNode * right){
ListNode * superHead = new ListNode(0);
ListNode * head = superHead;
ListNode * p = head;
while(left && right){
if(left->val < right->val){
p->next = left;
left = left->next;
}
else{
p->next = right;
right = right->next;
}
p = p->next;
}
if(left){
p->next = left;
}
if(right){
p->next = right;
}
head = superHead->next;
superHead->next = NULL;
delete superHead;
return head;
}
};
