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

 

posted @ 2018-01-27 14:54  bw98  阅读(257)  评论(1编辑  收藏  举报