148. Sort List

Sort a linked list in O(n log n) time using constant space complexity.
  • Total Accepted: 94368
  • Total Submissions: 342453
  • Difficulty: Medium
  • Contributors: Admin

分析


首先可以使用和147相同的思想,把数字复制到vector<int> 中,然后排序,再赋值回去
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * 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) {
        ListNode * p = head;
        vector<int> list;
        while(p != NULL){
            list.push_back(p->val);
            p = p->next;
        }
        sort(list.begin(), list.end());
        p = head;
       for(auto n : list){
           p->val = n;
           p = p->next;
       }
       return head;
    }
     
};

如果需要对list本身进行操作,则需要使用时间复杂度O(NlogN),那么能用到的排序只有
快排,归并,堆排

1. 因为list是单向的没法从后往前,所以需要快排的话,只能重新建立一个倒序的list,进行快排,平均时间复杂度O(NlogN),空间复杂度O(N)。下面的算法建立一个存储 ListNode * 的 vector 数组,从而实现双向访问
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == NULL) return head;
        ListNode * p = head;
        vector<ListNode *> plists;
        int len = 0;
        while(p != NULL){
            ++len;
            plists.push_back(p);
            p = p->next;
        }
         
        // quick sort
        listQsort(plists, 0, len - 1);
         
        return head;
    }
    void listQsort(vector<ListNode *> &plists, int left, int right){
        if(left >= right) return;
        int i = left, j = right;
        int key = plists[i + (j - i) / 2]->val;
        while(i <= j){
            while(i <= j && plists[i]->val < key) ++i;
            while(i <= j && plists[j]->val > key) --j;
            if(i <= j){
                int tmp = plists[i]->val;
                plists[i++]->val = plists[j]->val;
                plists[j--]->val = tmp;
            }
        }
        listQsort(plists, left, j);
        listQsort(plists, i, right);
    }
     
};
2. 归并排序,需要使用快慢指针,找到中间node位置,如果使用递归的话,需要考虑栈的消耗空间,所以时间复杂度O(NlogN),空间复杂度O(logN)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == NULL || head->next == NULL) return head;
         
        ListNode* slow = head;
        ListNode* fast = head;
        ListNode* pre = head;
        while(fast != NULL && fast->next != NULL){
            pre = slow;
            slow = slow->next;
            fast = fast->next->next;
        }
        /**如果这样写
         * ListNode* h2 = sortList(slow->next);
         * slow->next = NULL;
         * ListNode* h1 = sortList(head);
         * 会导致当list中只剩两个node,会永远死循环,不断递归调用下去
         */
        pre->next = NULL;
        ListNode* h1 = sortList(head);
        ListNode* h2 = sortList(slow);
         
        return mergeList(h1, h2);
    }
     
    ListNode* mergeList(ListNode* l1, ListNode* l2){
        if(l1 == NULL) return l2;
        if(l2 == NULL) return l1;
        ListNode * head = NULL;
        if(l1->val < l2->val){
            l1->next = mergeList(l1->next, l2);
            head = l1;
        }
        else{
            l2->next = mergeList(l1, l2->next);
            head = l2;
        }
        return head;
    }
};
3. 堆排序,需要建立一个最小堆,空间复杂度O(N),时间复杂度O(NlogN)

现在看来满足常量空间的只能是2,归并排序并将其写成非递归形式。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if(head == NULL || head->next == NULL) return head;
         
        ListNode* p = head;
        int len = 0;
        while(p != NULL){
            p = p->next;
            ++len;
        }
         
        ListNode dummy(0);
        dummy.next = head;
        for(int i = 1; i < len; i = i << 1){// 每次步长 翻倍
            ListNode* cur = dummy.next;
            ListNode* tail = &dummy, * left, * right;
            while(cur != NULL){
                left = cur;
                right = split(left, i);
                cur = split(right, i);
                tail = mergeList(left, right, tail);
            }
        }
        return dummy.next;
    }
     
    /**
     * split l + step sublist
     * return this sublist's next node
     
     **/
    ListNode* split(ListNode * l, int step){
        ListNode * pre;
        while(l != NULL && step--){
            pre = l;
            l = l->next;
        }
        if(l != NULL){
            pre->next = NULL;
        }
        return l;
    }
     
    /**
     * merge l1 and l2, then attach the new list to head->next
     * return the tail of the new list
     
     **/
    ListNode* mergeList(ListNode* l1, ListNode* l2, ListNode* head){
        ListNode dummy(0);
        ListNode * p = &dummy;
        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 = l2;
        if(l2 == NULL) p->next = l1;
        while(p->next != NULL) p = p->next;
        head->next = dummy.next;
        return p;
    }
};




原文地址:https://www.cnblogs.com/zhxshseu/p/fb49defeb2a3027a9963727f77c1fe11.html