Leetcode:Merge k Sorted Lists分析和实现
题目大意是传入一个链表数组lists,每个链表都由若干个链接的链表结点组成,并且每个链表结点记录一个整数。题目保证传入的链表中的整数按从小到大进行排序。
题目要求我们输出一个新的链表,这个链表中应该包含所有在lists中出现的整数,并且按从小到大排序。
我的思路:
这个问题解法应该很多。我采用的解法是分治算法,灵感来自于归并排序,因为归并排序的递归完成后也会涉及到将两个有序数组重组合并。
首先说明如何重组两个链表为一个有序链表,其思路源自于我们在玩扑克牌时对两堆有序扑克牌进行排序的手法:
1.我们从两叠有序扑克牌(正面向上)中,选取最小的牌面(即两叠扑克牌盖在最上面的两张牌中较小的牌),并加入到手牌中。
2.循环上一步直到有一叠牌被完全取走。
3.将剩下的一叠牌全部按序加入到手牌中。
由于始终选取较小的牌,以及两叠牌的从小到大排序的性质,能保证剩余的牌总是会不小于被选走的手牌。假设两叠牌共n张,由于这个过程中每次都会使得桌上的牌减少1,而减少到0时就会必定结束,因此上面的步骤最多只会执行n次,这n次中每一次都涉及一次比较和取牌(在计算机中是常量时间),因此我们可以认为要合并两个有序牌堆的时间复杂度为O(n)。
combine(A, B):
ai = 0, bi = 0
al = A.length, bl = B.length
result = empty-list
while(ai < al && bi < bl)
if(A[ai] <= B[bi])
insert A[ai] into result
ai = ai + 1
else
insert B[bi] into result
bi = bi + 1
while(ai < al)
insert A[ai] into result
ai = ai + 1
while(bi < bl)
insert B[bi] into result
bi = bi + 1
return result
但是题目已经指出了,k:=lists.length不一定为2。因此我们要通过分治算法将需要合并的链表数减少为2。其思路是先合并下标为0~k/2的链表,在合并k/2~k的链表。最后利用我们上面所说的洗牌算法将两个链表合并。
rec(lists, from, to) //合并lists[from], ... lists[to - 1]为一个链表,并返回合并的链表
if(from + 1 == to)
return lists[i]
half = (from + to) / 2
part1 = rec(lists, from, half)
part2 = rec(lists, half, to)
return combine(part1, part2)
上面就是我们归并算法的完整实现。先说明它能返回正确的结果。当to - from == 1时,此时需要排序的链表只有一个,只要直接返回这个链表就可以了。因此当to - from == 1时这个算法是正确的。假设当to-from<p时(p >1),这个算法能返回正确的结果。那么当to-from=p时,函数将排序lists中from~half段和half~to段的链表委托给递归函数。由于from < half < to,因此half-from<to-from=p,to-half<to-from=p,因此递归函数对于部分的排序返回了正确的结果,分别记为part1,part2,part1中保存了from~half段的合并结果,而part2中保存了half~to段的合并结果。最终利用我们已经说明过的洗牌合并法对合并part1和part2,因此最终得到的结果则是lists[from], ... lists[to - 1]的有序合并结果。这里用了一个关键的想法,即合并顺序不会改变最终结果。利用数学归纳法我们可以得出对于任意to-from>=1,rec函数都能返回正确的结果。
接下来说明这个算法的复杂度。
首先空间复杂度应该是O(n),因为函数递归发生在空间分配之前,因此当函数从下级递归中跳出时,最多持有与lists中保存的整数的拷贝(保存在part1和part2中),在combine函数中又会分配一次空间,但也最多只是part1和part2的长度的加总,因此,rec函数同时占据的空间量不会超过2n=O(n)。再提一下,这里由于没有要求我们不能使用传入的链表,因此假如我们直接通过操作链表进行排序而不分配额外的空间,那么空间复杂度就可以被优化到O(1)。
时间复杂度我们必须展开来看。一种简明的方式是将不同的递归深度区分开来 ,在同一递归深度中的时间复杂度为O(n)。比方说在第一级递归,我们对长度为k的lists进行合并,但是实际上发生在这一递归深度的只有调用combine的合并操作,其时间复杂度为O(n)。同样在第二级递归,我们分别对0~k/2和k/2~k进行排序,而发生在这一递归深度的实际的操作只有combine操作,两个combine操作正好涉及了lists[0~k]中所有的元素,因此时间复杂度也是O(n)。考虑到递归深度最大为log2(k),因此总的时间复杂度为O(n)*log2(k)=O(nlog2(k))。
最后提供一下java代码,13ms AC:
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length <= 1) {
return lists.length == 0 ? null : lists[0];
}
return mergeKLists(lists, 0, lists.length);
}
public ListNode mergeKLists(ListNode[] lists, int from, int to) {
if (to == from + 1) {
return lists[from];
}
int half = (from + to) / 2;
ListNode part1 = mergeKLists(lists, from, half);
ListNode part2 = mergeKLists(lists, half, to);
if (part1 == null || part2 == null) {
return part1 == null ? part2 : part1;
}
if (part1.val > part2.val) {
ListNode tmp = part1;
part1 = part2;
part2 = tmp;
}
ListNode traceNode1 = part1;
ListNode traceNode2 = part2;
ListNode formerNode1 = null;
ListNode formerNode2 = null;
while (traceNode1 != null && traceNode2 != null) {
while (traceNode1 != null && traceNode2 != null && traceNode1.val <= traceNode2.val) {
formerNode1 = traceNode1;
traceNode1 = traceNode1.next;
}
ListNode start = traceNode2;
while (traceNode1 != null && traceNode2 != null && traceNode2.val <= traceNode1.val) {
formerNode2 = traceNode2;
traceNode2 = traceNode2.next;
}
if (formerNode1 != null) {
formerNode1.next = start;
formerNode1 = formerNode2;
}
if (formerNode2 != null) {
formerNode2.next = traceNode1;
formerNode2 = null;
}
}
return part1;
}
}
Leetcode:Merge k Sorted Lists分析和实现的更多相关文章
- LeetCode: Merge k Sorted Lists 解题报告
Merge k Sorted Lists Merge k sorted linked lists and return it as one sorted list. Analyze and descr ...
- [LeetCode] Merge k Sorted Lists 合并k个有序链表
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 这 ...
- [Leetcode] Merge k sorted lists 合并k个已排序的链表
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. 思 ...
- LeetCode:Merge k Sorted Lists
题目链接 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexi ...
- LeetCode——Merge k Sorted Lists
Discription: Merge k sorted linked lists and return it as one sorted list. Analyze and describe its ...
- leetcode -- Merge k Sorted Lists add code
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. [ ...
- LeetCode Merge k Sorted Lists (链表)
题意 Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity ...
- LeetCode Merge k Sorted Lists 解决报告
https://oj.leetcode.com/problems/merge-k-sorted-lists/ 归并K已经整理阵列,和分析算法的复杂. 解决报告:无论是不考虑优化,最简单的实现是要重新走 ...
- LeetCode —— Merge k Sorted Lists
/* ** 算法的思路: ** 1.将k个链表的首元素进行建堆 ** 2.从堆中取出最小的元素,放到链表中 ** 3.如果取出元素的有后续的元素,则放入堆中,若没有则转步骤2,直到堆为空 */ #in ...
随机推荐
- get传输时,会将加号+ 转换为空格
解决办法: 前端: 替换加号为 ‘%2B’, 后端: 直接接收即可.
- [python] 排序的动态展示
两句闲话 本文所说的排序是指基于交换的排序.因此,按理来说,本文应该叫基于交换的排序的动态展示,但是这样太拗口了. 效果展示 最终效果如下. 实现方法 需要说明的是,在这里是通过pygame来实现图形 ...
- 21天学通C++_Day1
被阿里实习生的第一轮电话面试刷掉以后,幡然醒悟,发现以前学习的C++基础一点都不扎实.为了把基础打扎实,重新学习一遍:为了让自己不放弃,也顺便可以把当天学到的东西记录下来,开始了写博客. 学习书籍:& ...
- 【占位】HihoCoder 1160 : 攻城略地(并查集好题)
攻城略地 时间限制:2000ms 单点时限:1000ms 内存限制:256MB 描述 A.B两国间发生战争了,B国要在最短时间内对A国发动攻击.已知A国共有n个城市(城市编号1, 2, …, n),城 ...
- Python基本特殊方法之__new__
__new__()和不可变对象 __new__方法的一个用途是初始化不可变对象,__new()__方法中允许创建未初始化的对象,这允许我们在__init__()方法被调用之前先设置对象的属性 例:为f ...
- jenkins部署应用
1. 系统介绍 Jenkins系统提供了一键部署的作用,整个过程有从提测的分支抓取代码,编译,打包,把打的包部署在应用服务器上,基本有Service,Web和Worker等. 2. Jen ...
- zju 校队选拔 被虐记
选拔已经开始了三天才想起来写游记 QAQ.. 7.12 弱弱的Sky_miner来到了ZJU,过程中被热成狗... 然后见到了无数大二大三的大佬们,过程中被热成狗... 后来听靖哥哥说集训的注意事项, ...
- linux之使用rpmbuild打rpm包
linux之使用rpmbuild打rpm包 前言: 已从事linux运维工作数年,感觉自己还是个小菜鸟,没有大神那么的钻研的精神.只是单纯热爱,喜欢对着黑色的屏幕敲击命令,喜欢这种感觉.为什么要做RP ...
- HDOJ5877(dfs序+离散化+树状数组)
Weak Pair Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total ...
- Java:Java 清单
ylbtech-Java:Java 清单 1.返回顶部 2.返回顶部 3.返回顶部 4.返回顶部 5.返回顶部 6.返回顶部 作者:ylbtech出处:http://ylb ...