zoukankan      html  css  js  c++  java
  • LeetCode #23 Merge k Sorted Lists k链归并 优先队列

    Description


      

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

    实现链表版的 k 路归并并分析其复杂度。

    思路


      一看到归并且要求时间复杂度尽可能低,那么自然联想到 T(n) = O(nlgn)  的归并排序或堆排序,但是代码都比较长些,短时间内不易解决。有没有什么简单快捷地办法呢?有的,那就是利用最小堆实现 k 路归并。先把 k 条链的元素全部入堆,每次取出堆顶元素,去掉原先的链,再重新链成一串即可。

      由于STL已经帮我们实现了优先队列,所以做题时直接使用 priority_queue 即可,它的模板声明带有三个参数, priority_queue<Type, Container, Functional> 其中 Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。主要方法有五个:push(), top(), pop(), size(), empty(),已经满足了本题需要的操作,入堆,取堆顶元素并出堆,查看当前堆的大小,堆是否为空。  

      此外还需要定义优先级,第一种方法是重载 () ,如下面的第一个例子。此时的 cmp 叫做仿函数/函数对象(functor),是指重载了operator()运算符的类,它广泛用于泛型编程。函数的形参形式最好写成 “const Type& a” 的形式,并且将该成员函数用 const 修饰。类似如下形式:

    struct cmp{
        bool operator () (const Type& a, const Type& b) const
        {
            return a.dat > b.dat;
        }
    };

    priority_queue<Type, Container, cmp> pQueue; 

      或者,在类中重载 < 操作符,并重载为友元函数

    struct T {
        Data dat;
        friend bool operator < (const Type& a, const Type& b)
        {
            return a.dat > b.dat;
        }
    };
    
    priority_queue<T> pQueue;

      

      扯远了,本题算法如下,由于每个元素入堆的时间是 O(lgn) ,需要线性扫描入堆也就是 O(nlgn),出堆时间是 O(lgn) ,串成链的时间是Θ(1),需要线性地让全部元素出堆也就是 O(nlgn),所以总时间 T(n) = O(nlgn) + O(nlgn) + n * Θ(1) = O(nlgn)

    /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     ListNode *next;
     *     ListNode(int x) : val(x), next(NULL) {}
     * };
     */
    #include <iostream>
    #include <algorithm>
    
    struct cmp { 
        bool operator() (const ListNode* a, const ListNode* b) const
        {
            return (a->val > b->val);
        }
    };
    
    class Solution {
    public:
        ListNode* mergeKLists(vector<ListNode*>& lists) {
            priority_queue <ListNode*, vector<ListNode*>, cmp> pQueue;
            
            ListNode* lnode;
            for (auto c : lists) {
                lnode = c;
                while (lnode) {
                    pQueue.push (lnode);
                    lnode = lnode->next;
               }
            }
            
            if (pQueue.empty()) return NULL;
                
            ListNode *head, *p, *q;
            head = p = pQueue.top(); pQueue.pop();
            head->next =  p->next = NULL; //initialize first node of new linklist
            while (!pQueue.empty()) {           
                q = pQueue.top(); pQueue.pop();
                q->next = NULL; //broken pointer which was set previously
                p->next = q;
                p = q;
            }
            return head;
        }
    };
    View Code
    ————全心全意投入,拒绝画地为牢
  • 相关阅读:
    NanoProfiler
    NanoProfiler
    Open Source Cassandra Gitbook for Developer
    Android Fragment使用(四) Toolbar使用及Fragment中的Toolbar处理
    Android Fragment使用(三) Activity, Fragment, WebView的状态保存和恢复
    Android Fragment使用(二) 嵌套Fragments (Nested Fragments) 的使用及常见错误
    Android Fragment使用(一) 基础篇 温故知新
    Set up Github Pages with Hexo, migrating from Jekyll
    EventBus源码解析 源码阅读记录
    Android M Permission 运行时权限 学习笔记
  • 原文地址:https://www.cnblogs.com/Bw98blogs/p/8366075.html
Copyright © 2011-2022 走看看