一、题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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
二、代码
/**
* 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 static class ListNodeComparator implements Comparator<ListNode> {
// 构建升序比较器
@Override
public int compare(ListNode a, ListNode b) {
if (a.val < b.val) {
return -1;
} else if (a.val > b.val) {
return 1;
} else {
return 0;
}
}
}
public ListNode mergeKLists(ListNode[] lists) {
// 判断空情况
if (lists == null) {
return null;
}
// 将每一个链表的头节点先加入堆中
PriorityQueue<ListNode> pq = new PriorityQueue<ListNode>(new ListNodeComparator());
for (int i = 0; i < lists.length; i++) {
// 一定要确保这个节点不是null再加入,不然后面操作堆的时候会出现空指针异常。
if (lists[i] != null) {
pq.add(lists[i]);
}
}
// [[]、[]] 和 [[]]、[]这种情况,lists并不是Null,但是数组中却什么也没有,如果不判断这种情况在后面就会操作一个空的堆,就会出现空指针错误。
if (pq.isEmpty()) {
return null;
}
ListNode head = pq.poll();
if (head.next != null) {
pq.add(head.next);
}
ListNode tail = head;
ListNode temp = null;
// 依次将堆顶弹出,如果将弹出堆顶的next不是空,就将将弹出堆顶的next压入。将所有弹出的节点一次组合成一个链表
// 当堆中所有元素都弹出之后,最后形成的链表就是最终结果。
while (!pq.isEmpty()) {
temp = pq.poll();
tail.next = temp;
tail = temp;
if (tail.next != null) {
pq.add(tail.next);
}
}
return head;
}
}
三、解题思路
原理就是将所有链表的头节点先压入优先队列,通过优先级队列对压入的数据进行排序
然后再弹出堆顶节点,这个元素一定是当前所有节点中最小的,因为所有的链表也是升序链表。然后将弹出的这个节点的next节点压入优先级队列中。
再去执行相同的操作,弹出堆顶,将弹出堆顶的next压入优先级队列。这样就能保证每次都能依次的到剩余节点中最小的节点。
因为每一次将堆顶节点的next节点压入,就是为了保证在优先级队列中的节点,一定都是所有链表中剩余节点的最小节点,这样就能保证每次在堆中弹出的节点一定是剩余节点中最小的节点。