您的位置:首页 > 其它

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

2017-06-19 20:15 501 查看

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的博客。

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