您的位置:首页 > 其它

23.Merge K Sorted Lists

2015-06-29 20:48 239 查看
第一种方法:分治法。

思路:有点类似于MergeSort的思路,就是分治法,不了解MergeSort的朋友,请参见归并排序-维基百科,是一个比较经典的O(nlogn)的排序算法,还是比较重要的。思路是先分成两个子任务,然后递归求子任务,最后回溯回来。这个题目也是这样,先把k个list分成两半,然后继续划分,直到剩下两个list就合并起来,合并时会用到Merge
Two Sorted Lists这道题,不熟悉的朋友可以复习一下。

我们来分析一下上述算法的时间复杂度。假设总共有k个list,每个list的最大长度是n,那么运行时间满足递推式T(k)
= 2T(k/2)+O(n*k)。根据主定理,可以算出算法的总复杂度是O(nklogk)。如果不了解主定理的朋友,可以参见主定理-维基百科。空间复杂度的话是递归栈的大小O(logk)。

代码:

/**

 * Definition for singly-linked list.

 * struct ListNode {

 *     int val;

 *     ListNode *next;

 *     ListNode(int x) : val(x), next(NULL) {}

 * };

 */

class Solution {

public:

        ListNode* merge2(ListNode* left_p,ListNode* right_p){

                if(left_p==NULL) return right_p;

                if(right_p==NULL) return left_p;

                ListNode* result;

                ListNode* cur_p;

                if(left_p->val<=right_p->val){

                        result=left_p;

                        cur_p=left_p;

                        left_p=left_p->next;

                }

                else{

                        result=right_p;

                        cur_p=right_p;

                        right_p=right_p->next;

                }

                while(left_p!=NULL && right_p!=NULL){

                        if(left_p->val<=right_p->val){

                                cur_p->next=left_p;

                                cur_p=left_p;

                                left_p=left_p->next;

                        }else{

                                cur_p->next=right_p;

                                cur_p=right_p;

                                right_p=right_p->next;

                        }

                }

                if(left_p==NULL)

                        cur_p->next=right_p;

                else

                        cur_p->next=left_p;

                return result;

        }

        ListNode* devide(vector<ListNode*>& lists,int left,int right){

                if(left>=right) return lists[left];

                int mid=(left+right)/2;

                return merge2(devide(lists,left,mid),devide(lists,mid+1,right));

        }

        ListNode* mergeKLists(vector<ListNode*>& lists) {

                int len=lists.size();

                if(len<=0) return NULL;

                if(len==1) return lists[0];

                ListNode* result=devide(lists,0,len-1);

                return result;

        }
};

第二种方法:堆。
维护一个大小为k的堆,每次取堆顶的最小元素放到结果中,然后读取该元素的下一个元素放入堆中,重新维护好。因为每个链表是有序的,每次又是去当前k个元素中最小的,所以当所有链表都读完时结束,这个时候所有元素按从小到大放在结果链表中。这个算法每个元素要读取一次,即是k*n次,然后每次读取元素要把新元素插入堆中要logk的复杂度,所以总时间复杂度是O(nklogk)。空间复杂度是堆的大小,即为O(k)。代码如下:

堆用了STL里面的堆函数:

//比较函数,注意这里最小堆是用大于函数,比较奇怪。

bool cmp(ListNode* node1,ListNode* node2){

        if(node1->val>=node2->val){

            return true;

        }else{

            return false;

        }

    }

class Solution {

public:

    ListNode* mergeKLists(vector<ListNode*>& lists) {

        int len=lists.size();
//为了使用STL的堆函数,得先开辟一个数组来保存堆元素。

        ListNode** min_heap=new ListNode*[len+1];

        int size=0;

        for(int i=0;i<len;++i){

            if(lists[i]!=NULL){

                min_heap[size++]=lists[i];

            }

        }

        if(size==0){

            delete []min_heap;

            return NULL;

        }

        if(size==1){

            ListNode* result=min_heap[0];

            delete []min_heap;

            return result;

        }

        make_heap(&min_heap[0],&min_heap[size],cmp);

        ListNode *new_lists,*result;

        new_lists=min_heap[0];

        result=new_lists;

//取出第一个节点

        if(min_heap[0]->next!=NULL){

            min_heap[0]=min_heap[0]->next;

            make_heap(&min_heap[0],&min_heap[size],cmp);

        }else{

            pop_heap(&min_heap[0],&min_heap[size],cmp);

            size--;

        }

//开始入堆出堆的过程

        while(size>0){

            new_lists->next=min_heap[0];

            new_lists=new_lists->next;

            if(min_heap[0]->next==NULL){

                pop_heap(&min_heap[0],&min_heap[size],cmp);

                size--;

            }else{

                min_heap[0]=min_heap[0]->next;

                make_heap(&min_heap[0],&min_heap[size],cmp);

                /*上面两句也可以用下面三句代替

                pop_heap(&min_heap[0],&min_heap[size],cmp);

                min_heap[size-1]=min_heap[size-1]->next;

                push_heap(&min_heap[0],&min_heap[size],cmp);

                */

            }

        }

        delete []min_heap;

        return result;

    }

};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: