算法-堆、队列、分治法-合并 K 个升序链表
1 题目概述
1.1 题目出处
https://leetcode.cn/problems/merge-k-sorted-lists
1.2 题目描述
2 题解
2.1 队列
2.1.1 解题思路
将各个有序子链表放入队列,两两合并,最后队列中剩的最后的子链表就是合并后的结果。
2.1.2 代码
/**
* 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.length == 0) {
return null;
}
Queue<ListNode> queue = new LinkedList<>();
for(ListNode node : lists) {
if (node != null) {
queue.add(node);
}
}
while (queue.size() > 1) {
ListNode left = queue.poll();
ListNode right = queue.poll();
queue.add(mergeKLists(left, right));
}
return queue.poll();
}
private ListNode mergeKLists(ListNode left, ListNode right) {
ListNode head = new ListNode();
ListNode tmpH = head;
ListNode tmpL = left;
ListNode tmpR = right;
while (tmpL != null && tmpR != null) {
if (tmpL.val < tmpR.val) {
tmpH.next = tmpL;
tmpL = tmpL.next;
} else {
tmpH.next = tmpR;
tmpR = tmpR.next;
}
tmpH = tmpH.next;
}
if (tmpL == null) {
tmpH.next = tmpR;
}
if (tmpR == null) {
tmpH.next = tmpL;
}
return head.next;
}
}
2.1.3 时间复杂度
参考 https://leetcode.cn/problems/merge-k-sorted-lists/solutions/219756/he-bing-kge-pai-xu-lian-biao-by-leetcode-solutio-2/?envType=study-plan-v2&envId=top-interview-150
2.1.4 空间复杂度
O(logk)
递归会使用到 O(logk)空间代价的栈空间。
2.2 堆-由优先级队列实现
2.2.1 解题思路
- 将所有元素一次插入小顶堆
- 将小顶堆的所有元素依次取出并组成链表
- 最后得到的链表就是从小到大排列的链表
2.2.2 代码
/**
* 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) {
ListNode head = new ListNode();
if (lists.length == 0) {
return null;
}
PriorityQueue<ListNode> queue = new PriorityQueue<>((o1, o2) -> {
return o1.val - o2.val;
});
for (ListNode listNode : lists) {
if (null == listNode) {
continue;
}
ListNode tmp = listNode;
while (null != tmp) {
queue.add(tmp);
tmp = tmp.next;
}
}
ListNode tmp = queue.poll();
head.next = tmp;
while (queue.size() > 0) {
tmp.next = queue.poll();
tmp = tmp.next;
}
if (null != tmp) {
tmp.next = null;
}
return head.next;
}
}
2.2.3 时间复杂度
O(NKlogNK)
2.2.4 空间复杂度
O(NK)
2.3 堆-由自己实现堆-优化
2.2.1 解题思路
- 将K个队列的元素每次都拿1个插入小顶堆,组成一个大小为K的小顶堆
- 每次将小顶堆的堆顶元素取出,并将该元素的下一个元素放入小顶堆
- 最后得到的链表就是从小到大排列的链表
2.2.2 代码
/**
* 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; }
* }
*/
/**
* 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 {
private class MinHeap {
private List<ListNode> list = new ArrayList<>();
public void add(ListNode node) {
// 添加时,先把node放到小顶堆尾
list.add(node);
int i = list.size() - 1;
ListNode tmp = node;
while (i > 0) {
// 每次和父节点对比,
// 这是小顶堆,则如果当前节点比父节点更小,就和父节点交还位置
int parent = (i - 1) / 2;
if (tmp.val < list.get(parent).val) {
list.set(i, list.get(parent));
i = parent;
} else {
break;
}
}
// 最后i的位置就是合适位置了,将目标节点放入即可
list.set(i, tmp);
}
public ListNode poll() {
if (size() == 0) {
return null;
}
// 小顶堆取节点时,直接取首节点即val最小的节点
ListNode target = list.get(0);
if (size() == 1) {
list.remove(0);
return target;
}
// 将堆顶节点和尾节点交换位置,并从上至下开始调整堆
list.set(0, list.get(size() - 1));
list.remove(size() - 1);
int i = 0;
ListNode tmp = list.get(0);
while ((i * 2 + 1) < size()) {
int child = i * 2 + 1;
if (child < list.size() - 1 && list.get(child).val > list.get(child + 1).val) {
child = child + 1;
}
if (tmp.val > list.get(child).val) {
list.set(i, list.get(child));
i = child;
} else {
break;
}
}
list.set(i, tmp);
return target;
}
public int size() {
return list.size();
}
}
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
MinHeap heap = new MinHeap();
for(ListNode node : lists) {
if (node != null) {
heap.add(node);
}
}
ListNode dummpy = new ListNode();
ListNode tail = dummpy;
while (heap.size() > 0) {
ListNode node = heap.poll();
tail.next = node;
tail = node;
if (null != node.next) {
heap.add(node.next);
}
}
return dummpy.next;
}
}