LeetCode:Merge k Sorted Lists

简介:

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

合并k个有序的链表,我们假设每个链表的平均长度是n。这一题需要用到合并两个有序的链表子过程

 

算法1

最傻的做法就是先1、2合并,12结果和3合并,123结果和4合并,…,123..k-1结果和k合并,我们计算一下复杂度。

1、2合并,遍历2n个节点

12结果和3合并,遍历3n个节点

123结果和4合并,遍历4n个节点

123..k-1结果和k合并,遍历kn个节点

总共遍历的节点数目为n(2+3+…+k) = n*(k^2+k-2)/2, 因此时间复杂度是O(n*(k^2+k-2)/2) = O(nk^2),代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
  * 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;
         ListNode*res = lists[0];
         for ( int  i = 1; i < lists.size(); i++)
             res = merge2list(res, lists[i]);
         return  res;
     }
     
     ListNode *merge2list(ListNode *head1, ListNode*head2)
     {
         ListNode node(0), *res = &node;
         while (head1 && head2)
         {
             if (head1->val <= head2->val)
             {
                 res->next = head1;
                 head1 = head1->next;
             }
             else
             {
                 res->next = head2;
                 head2 = head2->next;
             }
             res = res->next;
         }
        if (head1)
             res->next = head1;
         else  if (head2)
             res->next = head2;
         return  node.next;
     }
};

算法2:利用分治的思想把合并k个链表分成两个合并k/2个链表的任务,一直划分,知道任务中只剩一个链表或者两个链表。可以很简单的用递归来实现。因此算法复杂度为T(k) = 2T(k/2) + O(nk),很简单可以推导得到算法复杂度为O(nklogk)

递归的代码就不贴了。下面是非递归的代码非递归的思想是(以四个链表为例):                   本文地址

1、3合并,合并结果放到1的位置

2、4合并,合并结果放到2的位置

再把1、2合并(相当于原来的13 和 24合并)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
  * 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) {
         int  n = lists.size();
         if (n == 0) return  NULL;
         while (n >1)
         {
             int  k = (n+1)/2;
             for ( int  i = 0; i < n/2; i++)
                 lists[i] = merge2list(lists[i], lists[i + k]);
             n = k;
         }
         return  lists[0];
     }
     
     ListNode *merge2list(ListNode *head1, ListNode*head2)
     {
         ListNode node(0), *res = &node;
         while (head1 && head2)
         {
             if (head1->val <= head2->val)
             {
                 res->next = head1;
                 head1 = head1->next;
             }
             else
             {
                 res->next = head2;
                 head2 = head2->next;
             }
             res = res->next;
         }
         if (head1)
             res->next = head1;
         else  if (head2)
             res->next = head2;
         return  node.next;
     }
};

 


算法3:维护一个k个大小的最小堆,初始化堆中元素为每个链表的头结点,每次从堆中选择最小的元素加入到结果链表,再选择该最小元素所在链表的下一个节点加入到堆中。这样当堆为空时,所有链表的节点都已经加入了结果链表。元素加入堆中的复杂度为O(longk),总共有kn个元素加入堆中,因此,复杂度也和算法2一样是O(nklogk)

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





本文转自tenos博客园博客,原文链接:http://www.cnblogs.com/TenosDoIt/p/3673188.html,如需转载请自行联系原作者

目录
相关文章
Leetcode 4. Median of Two Sorted Arrays
题目描述很简单,就是找到两个有序数组合并后的中位数,要求时间复杂度O(log (m+n))。 如果不要去时间复杂度,很容易就想到了归并排序,归并排序的时间复杂度是O(m+n),空间复杂度也是O(m+n),不满足题目要求,其实我开始也不知道怎么做,后来看了别人的博客才知道有个二分法求两个有序数组中第k大数的方法。
80 0
Leetcode Find Minimum in Rotated Sorted Array 题解
对一个有序数组翻转, 就是随机取前K个数,移动到数组的后面,然后让你找出最小的那个数,注意,K有可能是0,也就是没有翻转。
108 0
LeetCode 167 Two Sum II - Input array is sorted(输入已排序数组,求其中两个数的和等于给定的数)
给定一个有序数组和一个目标值 找出数组中两个成员,两者之和为目标值,并顺序输出
127 0
|
算法 Python
LeetCode 108. 将有序数组转换为二叉搜索树 Convert Sorted Array to Binary Search Tree
LeetCode 108. 将有序数组转换为二叉搜索树 Convert Sorted Array to Binary Search Tree
|
算法 测试技术
LeetCode 88. 合并两个有序数组 Merge Sorted Array
LeetCode 88. 合并两个有序数组 Merge Sorted Array
LeetCode 21. 合并两个有序链表 Merge Two Sorted Lists
LeetCode 21. 合并两个有序链表 Merge Two Sorted Lists
|
12月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
174 6
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
|
Python
【Leetcode刷题Python】剑指 Offer 32 - III. 从上到下打印二叉树 III
本文介绍了两种Python实现方法,用于按照之字形顺序打印二叉树的层次遍历结果,实现了在奇数层正序、偶数层反序打印节点的功能。
132 6
|
搜索推荐 索引 Python
【Leetcode刷题Python】牛客. 数组中未出现的最小正整数
本文介绍了牛客网题目"数组中未出现的最小正整数"的解法,提供了一种满足O(n)时间复杂度和O(1)空间复杂度要求的原地排序算法,并给出了Python实现代码。
290 2
|
12月前
|
数据采集 负载均衡 安全
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口
本文提供了多个多线程编程问题的解决方案,包括设计有限阻塞队列、多线程网页爬虫、红绿灯路口等,每个问题都给出了至少一种实现方法,涵盖了互斥锁、条件变量、信号量等线程同步机制的使用。
182 3
LeetCode刷题 多线程编程九则 | 1188. 设计有限阻塞队列 1242. 多线程网页爬虫 1279. 红绿灯路口

热门文章

最新文章