zoukankan      html  css  js  c++  java
  • 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;
        }
    };




  • 相关阅读:
    并发编程bug的源头
    lambda表达式
    如何学习并发编程
    开篇词
    试述软件的概念和特点?软件复用的含义?构件包括哪些?
    软件生存周期及其模型是什么?
    一台客户端有三百个客户与三百个客户端有三百个客户对服务器施压,有什么区别?
    在搜索引擎中输入汉字就可以解析到对应的域名,请问如何用LoadRunner进行测试。
    给你一个网站,你如何测试?
    你在测试中发现了一个bug,但是开发经理认为这不是一个bug,你应该怎样解决?
  • 原文地址:https://www.cnblogs.com/zhxshseu/p/fb49defeb2a3027a9963727f77c1fe11.html
Copyright © 2011-2022 走看看