Java 题解 | #牛群的合并#
牛群的合并
https://www.nowcoder.com/practice/d0cb24e1494e4f45a4b7d1a17db0daef
本题考察的知识点包括:链表的基本数据结构、(我这个代码还用到了优先队列),因为每个链表都是排序的,按照升序排序还是很简单的。
如果想写其他的解法,感觉可以考虑指针。
解决方案通过使用优先队列(最小堆)来管理所有链表的节点。首先,我们将每个链表的头节点添加到优先队列中。每次从优先队列中取出最小的节点,并将其添加到合并后链表中。然后,如果被取出的节点有下一个节点,则将下一个节点添加回优先队列中。重复这个过程,直到优先队列为空。最后,返回合并后链表的头节点。
- 检查输入参数 lists 是否为 null 或者空数组。如果是,则返回 null,因为没有需要合并的链表。
- 创建一个优先队列(最小堆) minHeap 来存储链表的节点。我们将使用 Comparator.comparingInt 方法传入一个lambda 函数,以便根据节点的值进行比较。
- 使用 for 循环遍历 lists 数组的每个链表,并将链表的头节点添加到优先队列 minHeap 中。注意,在添加之前,需要先检查当前链表是否为空。
- 创建一个哑节点 dummy 作为合并后链表的头节点,同时创建一个指针 curr 指向当前节点,初始时指向 dummy 节点。
- 进入一个循环,当优先队列 minHeap 不为空时,执行以下操作:
- 使用 minHeap.poll() 方法取出最小的节点 smallest。
- 将 smallest 节点连接到合并后链表中,即 curr.next = smallest。
- 更新 curr 指针,让其指向刚刚插入的节点,即 curr = curr.next。
- 检查 smallest 节点是否还有下一个节点,如果有,则将其添加回优先队列 minHeap 中,即 minHeap.offer(smallest.next)。
- 当循环结束时,所有的链表都已经合并到了合并后的链表中。返回哑节点 dummy 的下一个节点作为合并后链表的头节点。
这个解决方案的时间复杂度是 O(N log K),其中 N 是所有链表中节点的总数,K 是链表的数量。每次从优先队列中取出最小值的操作的时间复杂度是 log K,该操作最多执行 N 次
import java.util.*;
/*
* public class ListNode {
* int val;
* ListNode next = null;
* public ListNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param lists ListNode类一维数组
* @return ListNode类
*/
public ListNode mergeKLists (ListNode[] lists) {
// write code here
if (lists == null || lists.length == 0) {
return null;
}
// 使用优先队列(最小堆)来存储链表节点
PriorityQueue<ListNode> minHeap = new PriorityQueue<>(Comparator.comparingInt(node -> node.val));
// 初始化优先队列,将每个链表的头节点加入队列中
for (ListNode list : lists) {
if (list != null) {
minHeap.offer(list);
}
}
// 创建一个哑节点作为合并后链表的头节点
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
// 从优先队列中取出最小的节点,并将其下一个节点添加到队列中
while (!minHeap.isEmpty()) {
ListNode smallest = minHeap.poll();
curr.next = smallest;
curr = curr.next;
if (smallest.next != null) {
minHeap.offer(smallest.next);
}
}
return dummy.next;
}
}

三奇智元机器人科技有限公司公司福利 82人发布