[leetcode] Sort List


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;
    }
};

Untitled

Leave a comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.