题目:

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1:

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6
示例 2:

输入:lists = []
输出:[]
示例 3:

输入:lists = [[]]
输出:[]

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

参考@【王尼玛】的解题思路

一、小根堆

如图:4个链表中的最小值,一定来自黄色的部分,黄色的部分就是一个小根堆。
这个堆的元素个数是lists中链表的个数,初始时只是将每个链表的头结点放入堆中,建立完初始的堆后,就不断的从堆中获取节点,如果获取到的节点不为空,即还有下一个节点,那么就将下一个节点放到堆中。

代码:

 1 /**
2 * Definition for singly-linked list.
3 * public class ListNode {
4 * int val;
5 * ListNode next;
6 * ListNode() {}
7 * ListNode(int val) { this.val = val; }
8 * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
9 * }
10 */
11 class Solution {
12 public ListNode mergeKLists(ListNode[] lists) {
13 if(lists == null || lists.length == 0) return null;
14 PriorityQueue<ListNode> queue = new PriorityQueue(new Comparator<ListNode>(){
15 public int compare(ListNode l1, ListNode l2){
16 //升序
17 return l1.val - l2.val;
18 }
19 });
20 ListNode dummy = new ListNode(0);
21 ListNode cur = dummy;
22 //把每个链表的头结点放进队列中
23 for(ListNode node: lists){
24 if(node != null){
25 queue.add(node);
26 }
27 }
28 while(!queue.isEmpty()){
29 cur.next = queue.poll();
30 cur = cur.next;
31 //将当前结点的下一个结点也放入队列中
32 if(cur.next != null){
33 queue.add(cur.next);
34 }
35 }
36 return dummy.next;
37 }
38 }

 二、分治和合并

先将整个链表在中间进行拆分成两部分,然后再对这两部分继续拆分,直到拆分成最小单元(只有一个链表)时,再进行两两进行合并,合并后以当前合并后的链表为新的链表再与其他的链表进行合并。看图更容易理解

 代码:

/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length == 0) return null;
return mergeTwolists(lists, 0, lists.length - 1);
}
//分治
private ListNode mergeTwolists(ListNode[] lists, int start, int end){
if(start == end){
return lists[start];
}
int mid = start + (end - start) / 2;
ListNode l1 = mergeTwolists(lists, start, mid);
ListNode l2 = mergeTwolists(lists, mid+1, end);
return merge(l1, l2);
}
//合并
private ListNode merge(ListNode a, ListNode b){
if(a == null || b == null){
return (a == null) ? b : a;
}
if(a.val < b.val){
a.next = merge(a.next, b);
return a;
}else{
b.next = merge(a, b.next);
return b;
} }
}

小知识:

1.compare(Object o1, Object o2) 方法,比较o1和o2的大小:

如果要按照升序排序,
则 o1小于o2返回 -1,o1与o2相等返回 0,01大于02返回 1 如果要按照降序排序
则 o1小于o2返回 1,o1与o2相等返回 0,01大于02返回 -1

2.优先队列:优先队列PriorityQueue是Queue接口的实现,可以对其中元素进行排序

常用方法:

peek()//返回队首元素

poll()//返回队首元素,队首元素出队列

add()//添加元素

size()//返回队列元素个数

isEmpty()//判断队列是否为空,为空返回true,不空返回false

优先队列中的元素可以默认自然排序或者通过提供的Comparator(比较器)在队列实例化的时排序。(不指定Comparator时默认为最小堆)

 1 PriorityQueue<Integer> heap = new PriorityQueue<Integer>(new Comparator<Integer>() {
2 @Override
3 public int compare(Integer o1, Integer o2) {
4 //升序(小顶堆)
5 return o1 - o2;
6 或者这样写:
7 //降序(大顶堆)
8       return o2 - o1;
9 }
10 });

总结:

小顶堆, return 前减后(o1-o2);
大顶堆, return 后减前(o2-o1);

在堆中,比较器的使用方式为:若返回值>=0,则表示不要交换,否则,需要交换。所以我们只需要认清传入的两个参数,o1o2哪一个是谁我们就可以控制其是否要交换,只需要记住,o1永远是新的,在插入时是child,删除时是parent。

力扣23(java)-合并k个升序链表(困难)的更多相关文章

  1. 浅谈归并排序:合并 K 个升序链表的归并解法

    在面试中遇到了这道题:如何实现多个升序链表的合并.这是 LeetCode 上的一道原题,题目具体如下: 用归并实现合并 K 个升序链表 LeetCode 23. 合并K个升序链表 给你一个链表数组,每 ...

  2. 【每日一题】【小根堆&边出队边入队后续节点&注意判空】23. 合并K个升序链表-211128/220213

    给你一个链表数组,每个链表都已经按升序排列. 请你将所有链表合并到一个升序链表中,返回合并后的链表. 答案1(参数是数组): /** * Definition for singly-linked li ...

  3. [LeetCode题解]23. 合并K个升序链表 | 分治 + 递归

    方法一:分治 + 递归 解题思路 在21. 合并两个有序链表,我们知道如何合并两个有序链表.而本题是合并 k 个有序链表,可以通过大问题拆分成小问题解决,即把 k 个链表,拆分成 k/2 个链表组,俩 ...

  4. LeetCode-23 合并K个升序链表

    来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/merge-k-sorted-lists 题目描述 给你一个链表数组,每个链表都已经按升序排列. ...

  5. Leetcode(23)-合并K个排序链表

    合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [   1->4->5,   1->3->4,   2->6 ] 输出: 1-&g ...

  6. 【LeetCode】23. Merge k Sorted Lists 合并K个升序链表

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人公众号:负雪明烛 本文关键词:合并,链表,单链表,题解,leetcode, 力扣,Py ...

  7. 力扣Leetcode 21. 合并两个有序链表

    合并两个有序链表 将两个升序链表合并为一个新的升序链表并返回.新链表是通过拼接给定的两个链表的所有节点组成的. 示例: 输入:1->2->4, 1->3->4 输出:1-> ...

  8. 【LeetCode 23】合并K个排序链表

    题目链接 [题解] 会归并排序吧? 就把这K个链表当成是K个数字就好. 然后做归并排序. 因为归并排序的时候本来就会有这么一个过程. [l..mid]和[mid+1..r]这两段区间都是有序的了已经. ...

  9. LeetCode-023-合并K个升序链表

    合并K个升序链表 题目描述:给你一个链表数组,每个链表都已经按升序排列. 请你将所有链表合并到一个升序链表中,返回合并后的链表. 示例说明请见LeetCode官网. 来源:力扣(LeetCode) 链 ...

  10. Java实现 LeetCode 23 合并K个排序链表

    23. 合并K个排序链表 合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ 1->4->5, 1->3->4, 2->6 ] 输 ...

随机推荐

  1. vscode 自动格式化md文件,搞得很是郁闷,加入 [markdown] 自定义配置 "editor.formatOnSave": false 搞定了。

    上下文: vscode做vue的项目开发,需要对代码进行格式化,用的vetur插件 正常来讲,代码保存的时候,需要进行格式化,所以配置文件会写成 "editor.formatOnSave&q ...

  2. vue遇到拖拽动态生成组件怎么办?[转]

    知识点 主要是关注 动态生成 vue组件,这里是Vue2.0的demo Vue.Draggable 拖拽库 Vue.extend() 挂载 com.$mount() 生成组件 this.$refs.c ...

  3. git clone error: RPC failed; curl 18 transfer closed with outstanding read data remaining

    备忘 git clone比较大的工程时,出现这种错误:error: RPC failed; curl 18 transfer closed with outstanding read data rem ...

  4. 百度api经历

    底部参考文档,欢迎点击:https://www.runoob.com/http/http-content-type.html 这两天遇到了点糟心事,因为小伙伴走了.然后事情起因是这样的,来了个任务封装 ...

  5. 使用Servlet实现文件下载

    一位朋友最近在学习JavaWeb开发,开始学习文件下载操作,他自己尝试着去网上看一些教程,总的来说也不是太了解,就让我和他说说,如何实现文件下载功能.我和他说了一下大致的思路,主要分为前端和后端两部分 ...

  6. 5G+实时云渲染,助力虚拟仿真实训教学升级

    随着新冠疫情走向全球大流行的发展趋势,学校教育被迫迁徙到线上教学平台,供需平衡被打破,疫情让"在线教学"成为"口罩式的刚需". 我们看到互联网+教育带来便利的同 ...

  7. 实时云渲染 VS 本地渲染,全面横向对比

    不少用户不能理解,为什么要选用实时云渲染,而不用本地的电脑进行渲染显示?本文将通过各个方面来对比两种模式的优劣支持,帮助您更全面了解实时云渲染和本地渲染. 一.便携性对比 由于GPU对机箱空间有要求, ...

  8. 项目性能优化—使用JMeter压测SpringBoot项目

    项目性能优化-使用JMeter压测SpringBoot项目 我们的压力测试架构图如下: 配置JMeter 在JMeter的bin目录,双击jmeter.bat 新建一个测试计划,并右键添加线程组: 进 ...

  9. drools执行String规则或执行某个规则文件

    1.背景 此处主要记录一下2个小的知识点,防止以后忘记. 1.如何在drools中执行某个drl文件. 2.如果我们的规则是一个String类型的字符串,那么该如何执行. 2.实现 2.1 执行指定的 ...

  10. Java面试题【3】

    20)什么是线程安全? 含义:当多个线程访问某个方法时,不管你通过怎样的调用方式或者说这些线程如何交替的执行,我们在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以 ...