[Leetcode] Merge k sorted lists 合并k个已排序的链表

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

 思路:这题最容易想到的是,(假设有k个链表)链表1、2合并,然后其结果12和3合并,以此类推,最后是123--k-1和k合并。至于两链表合并的过程见merge two sorted lists的分析。复杂度的分析见JustDoIT的博客。算法复杂度:假设每个链表的平均长度是n,则1、2合并,遍历2n个节点;12结果和3合并,遍历3n个节点;....123...k-1的结果和k合并,遍历kn个节点,总共遍历n(2+3+4+....k)=n*(k^2+k-2)/2,因此时间复杂度是O(n*(k^2+k-2)/2)=O(nk^2)。     其次,可以想到用分治的思想,两两合并直至最后。

针对方法一,

 1 class Solution {
 2 public:
 3     //用向量存储链表
 4     ListNode *mergeKLists(vector<ListNode *> &lists) 
 5     {
 6         if(lists.size()==0) return NULL;
 7         ListNode *res=lists[0];     //取出第一个链表
 8         for(int i=1;i<lists.size();i++)     //反复调用
 9             res=mergeTwoList(res,lists[i]);
10 
11         return res;    
12     }
13 
14     //归并排序
15     ListNode *mergeTwoList(ListNode *head1,ListNode *head2)
16     {
17         ListNode node(0);   //创建头结点的前置结点
18         ListNode *res=&node;
19         while(head1&&head2)
20         {
21             if(head1->val<=head2->val)
22             {
23                 res->next=head1;
24                 head1=head1->next;
25             }
26             else
27             {
28                 res->next=head2;
29                 head2=head2->next;
30             }
31             res=res->next;
32         }
33 
34         if(head1)
35             res->next=head1;
36         else if(head2)
37             res->next=head2;
38         
39         return node.next;
40     }
41 };

针对方法二:比较难想的是,两两合并时,链表的选取。

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode(int x) : val(x), next(NULL) {}
 7  * };
 8  */
 9 class Solution {
10 public:
11     ListNode *mergeKLists(vector<ListNode *> &lists) 
12     {
13         int len=lists.size();
14         if(len==0)
15             return NULL;
16 
17         while(len>1)
18         {
19             int k=(len+1)>>1;
20 
21             for(int i=0;i<len/2;++i)
22             {
23                 lists[i]=mergeTwoLists(lists[i],lists[i+k]);
24             }
25             len=k;
26         }    
27         return lists[0];
28     }
29 
30     ListNode *mergeTwoLists(ListNode *head1,ListNode *head2)
31     {
32         ListNode *nList=new ListNode(-1);
33         nList->next=head1;
34         ListNode *pre=nList;
35 
36         while(head1&&head2)
37         {
38             if(head1->val >head2->val)
39             {
40                 pre->next=head2;
41                 head2=head2->next;
42             }
43             else
44             {
45                 pre->next=head1;
46                 head1=head1->next;
47             }
48             pre=pre->next;
49         }
50 
51         if(head1)
52         {
53             pre->next=head1;
54         }
55         else   
56             pre->next=head2;
57 
58         return nList->next;    
59     }
60 };

 

还有一种方法是最小堆的方法,维护一个大小为k的最小堆,初始化堆中的元素为每个链表的表头,它们会自动排好序,然后取出其中的最小元素介入新的链表中,然后,将最小元素的后继压入堆中,下次再从堆中选取最小的元素。元素加入堆中的复杂度为O(longk),总共有kn个元素加入堆中,因此,复杂度也和算法2一样是O(nklogk)。具体代码如下:

 1 class Solution 
 2 {
 3 private:
 4 struct cmp
 5 {
 6     bool operator()(const ListNode *a,const ListNode *b)
 7     {
 8         return a->val >b->val;
 9     }
10 }
11 public:
12     //用向量存储链表
13     ListNode *mergeKLists(vector<ListNode *> &lists) 
14     {
15         int n=lists.size();
16         if (n==0) return NULL;
17 
18         ListNode node(0);
19         ListNode *res=&node;
20 
21         priority_queue<ListNode*,vector<ListNode*>,cmp> que;
22 
23         for(int i=0;i<n;i++)
24         {
25             if(lists[i])
26                 que.push(list[i]);
27         }
28 
29         while(! que.empty())
30         {
31             ListNode *p=que.top();
32             que.pop();
33             res->next=p;
34             res=p;
35 
36             if(p->next)
37                 que.push(p->next);
38         }
39 
40         return node.next;
41     }
42 }

 

此篇中,有很多分析过程都是来自JustDoITGrandyang的博客。

posted @ 2017-06-19 20:15  王大咩的图书馆  阅读(530)  评论(0编辑  收藏  举报