[leetcode] Merge k Sorted Lists


Merge k Sorted Lists

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

Tag: divide and conquer, linked list, heap

update 9/22/2015

Merge sort the k lists. O(knlogk) in time, O(1)

//merge these 
/**
 * 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.size() == 0) return NULL;
        return _mergeKLists(lists, 0, lists.size());
    }
    
    //not include end, include start
    ListNode * _mergeKLists(vector<ListNode*>& lists, int start, int end){
        //base case
        if(end - start == 1){
            return lists[start];
        }
        int mid = start + (end - start) / 2;
        ListNode * l1 = _mergeKLists(lists, start, mid);
        ListNode * l2 = _mergeKLists(lists, mid, end);
        
        ListNode dummyNode = ListNode(0);
        ListNode *tail = &dummyNode;
        while(l1 != NULL && l2 != NULL){
            ListNode*& p = l1->val < l2->val ? l1: l2;
            tail->next = p;
            tail = tail->next;
            p = p->next;
        }
        tail->next = l1 == NULL? l2: l1;
        return dummyNode.next;
    }
};

 

遇到的第一个hard题,果然够味道。

版本一,用暴力搜,每次从k个lists中找到最小值,链到result里,再更新最小值所在的list。

空间复杂度O(1),时间复杂度大约为O(k*k*n)。k为lists数,n为每个list里平均元素数。

解决了输入为空的问题,版本一遇到了超时。(Time Limit Exceeded)

挂在了k很大的一个测试上。

[{7},{49},{73},{58},{30},{72},{44},{78},{23},{9},{40},{65},{92},{42},{87},{3….大约有几千个。

/**
 * 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) {
        ListNode * head = NULL;
        ListNode * tail = NULL;
        ListNode * p = NULL;
        vector<ListNode *>::iterator it,idx;
        //lists is empty
        if (lists.empty()){
            return NULL;
        }
        
        //some listnode are empty
        if (lists.size() > 0){
            for(it = lists.begin(); it != lists.end(); it++){
                if (*it == NULL){
                    lists.erase(it);
                    it--; // this is important, since iterator should be decreased after erase operation
                }
            }
        }
        
        while(lists.size() > 0){
            int min = lists[0]->val;
            idx = lists.begin();
            for(it = lists.begin() + 1; it != lists.end(); it++){
                if ((*it)->val < min){
                    min = (*it)->val;
                    idx = it;
                }
            }
            
            if (head == NULL){
                head = tail = *idx;
            }
            else{
                tail->next = *idx;
                tail = *idx;
            }
            if ((*idx)->next == NULL){
                lists.erase(idx);
            }
            else{
                *idx = (*idx)->next;
            }
            
        }
        return head;
    }
};

1.20更新:

看了tag,发现要用堆来做。今天复习了分析算法时间复杂度和堆的知识,自己实现了一个堆算法。又学了stl中堆的用法(priority queue)。解决了这道题目。

其中要注意,利用priority_queue时,要查它的函数说明http://en.cppreference.com/w/cpp/container/priority_queue

自己写一个compare类,重载'()’操作符,完成自己的比较需求。

版本二:

利用堆排序,每次取出堆顶元素后,向后移动元素所在listnode的指针,如果为空的话则舍弃,如果不空的话重新插入堆中。不断维护该堆。

记n为每个list中的平均元素个数,k为list数

时间复杂度为O(k*n*logk),空间复杂度为O(k)

C++代码:

/**
 * 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 * p1, const ListNode * p2) const{
        if (p1->val <= p2->val){
            return false;
        }
        
        else{
            return true;
        }
    }
};
class Solution {
public:
    ListNode *mergeKLists(vector<ListNode *> &lists) {
        vector<ListNode *>::iterator it;
        
        ListNode * head = NULL;
        ListNode * tail = NULL;
        ListNode * p = NULL;
        //lists is empty
        if (lists.empty()){
            return NULL;
        }
        
        //some elements in lists are empty
        for(it = lists.begin(); it != lists.end(); it++){
            if (*it == NULL){
                lists.erase(it);
                it--;
            }
        }
        
        if(lists.empty()){
            return NULL;
        }
        
        priority_queue<ListNode *, vector<ListNode *>, cmp>pq(cmp(), lists);
        
        //handle the first element
        p = pq.top();
        pq.pop();
        head = tail = p;
        p = p->next;
        if (p != NULL){
            pq.push(p);
        }
        
        //loop all the elements
        while(!pq.empty()){
            p = pq.top();
            pq.pop();
            
            tail->next = p;
            tail = tail->next;
            
            p = p->next;
            if(p != NULL){
                pq.push(p);
            }
        }
        
        tail->next = NULL;
        return head;
        
    }
        
};
程序运行效率

程序运行效率

待完善:
用分治算法。

Leave a comment

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.