• [LeetCode] Merge k Sorted Lists


    https://oj.leetcode.com/problems/merge-k-sorted-lists/

    Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

    Solution:

    1. O(nk2) runtime, O(1) space – Brute force:

    The brute force approach is to merge a list one by one. For example, if the lists = [l1, l2, l3, l4], we first merge l1 and l2, then merge the result with l3, and finally l4.

    To analyze its time complexity, we are going to assume there are a total of k lists, and each list is of size n. There will be a total of k–1 merge operations. The first merge operation will be two lists of size n, therefore in the worst case there could be n + n comparisons. The second merge operation will be two lists of size 2n and n. Notice that each merge increase the size of the merged lists by n. Therefore, the total number of comparisons required is 2n + 3n + 4n + … + kn = n(k(k+1)/2 -1) = O(nk2).

    2. O(nklogk) runtime, O(k) space – Heap:
    We could use a min heap of size k. The heap is first initialized with the smallest element from each list. Then as we extract the nodes out from the heap, we must remember to insert its next node into the heap. As each insert operation into the heap costs log(k) and there are a total of nk elements, the total runtime complexity is O(nklogk).

    Ignoring the extra space that is used to store the output list, we only use extra space of O(k) due to the heap.

    /**
     * Author : Acjx
     * Email  : zhoujx0219@163.com
     */
    
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    
    class Cmp
    {
        public:
            bool operator() (const ListNode *lhs, const ListNode *rhs)
            {
                return lhs->val > rhs->val;
            }
    };
    
    class Solution 
    {
    public:
        ListNode *mergeKLists(vector<ListNode *> &lists) 
        {
            if (lists.empty()) return NULL;
            
            priority_queue<ListNode, vector<ListNode *>, Cmp> queue;
            
            for (ListNode *&nodePtr : lists)
            {
                if (nodePtr != NULL)
                {
                    queue.push(nodePtr);
                }
            }
            
            ListNode *dummyHead = new ListNode(0);
            ListNode *p = dummyHead;
            while (!queue.empty())
            {
                ListNode *nodePtr = queue.top();
                queue.pop();
                p->next = nodePtr;
                p = p->next;
                if (nodePtr->next != NULL)
                {
                    queue.push(nodePtr->next);
                }
            }
            
            return dummyHead->next;
        }
    };

    3. O(nk log k) runtime, O(1) space – Divide and conquer using two way merge:
    If you still remember how merge sort works, we can use a divide and conquer mechanism to solve this problem. Here, we apply the merge two lists algorithm from Article[Merge Two Sorted Lists].

    Basically, the algorithm merges two lists at a time, so the number of lists reduces from:

    k –> k/2 –> k/4 –> … –> 2 –> 1

    Similarly, the size of the lists increases from (Note that the lists could subdivide itself at most log(k) times):

    n –> 2n –> 4n –> … –> 2logkn      

    Therefore, the runtime complexity is:

    k * n + k/2 * 2n + k/4 * 4n + … + 2logkn * 1
    = nk + nk + nk + … + nk
    = nklogk

    Since we are implementing this divide and conquer algorithm iteratively, the space complexity is constant at O(1), yay!

    /**
     * Author : Acjx
     * Email  : zhoujx0219@163.com
     */
    
    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    class Solution 
    {
    public:
        ListNode *mergeKLists(vector<ListNode *> &lists) 
        {
            if (lists.empty()) return NULL;
            
            int end = lists.size() - 1;
            while (end > 0)
            {
                int begin = 0;
                while (begin < end)
                {
                    lists[begin] = merge2Lists(lists[begin], lists[end]);
                    ++begin;
                    --end;
                }
            }
            return lists.at(0);
        }
        
    private:
        ListNode *merge2Lists(ListNode *l1, ListNode *l2)
        {
            ListNode *dummyHead = new ListNode(0);
            ListNode *p = dummyHead;
            
            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 = l1;
            if (l2 != NULL) p->next = l2;
            
            return dummyHead->next;
        }
    };
  • 相关阅读:
    Https协议详解
    python3爬虫之入门和正则表达式
    浅谈httpsssl数字证书
    Linux常见配置文件
    标准C++中的string类的用法总结
    SourceInsight中 加namespace宏后,无法跳转问题解决
    ubuntu 12.04安装vmtools 问题解决
    Prolific PL2303 usb 转串口Win8 Win8.1驱动
    大津法阈值法代码
    opencv常用函数备忘
  • 原文地址:https://www.cnblogs.com/jianxinzhou/p/4314404.html
Copyright © 2020-2023  润新知