题目
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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 = [[]]
输出:[]
题解一 优先队列
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0||lists==null){
return null;
}
PriorityQueue<ListNode> queue=new PriorityQueue<>(lists.length,new Comparator<ListNode>(){
public int compare(ListNode n1,ListNode n2){
if(n1.val<n2.val){
return -1;
}else if(n1.val==n2.val){
return 0;
}else{
return 1;
}
}
});//PriorityQueue(int initialCapacity, Comparator<? super E> comparator)使用指定的初始容量创建一个 PriorityQueue,并根据指定的比较器对元素进行排序。
for(ListNode n:lists){//全部加入队列
if(n!=null)queue.add(n);
}
//再一个个取出来放到答案里,答案记得加一个虚拟头节点,便于操作
ListNode dummyHead=new ListNode(0);
ListNode p=dummyHead;
while(!queue.isEmpty()){
p.next=queue.poll();//先得到p的下一个节点的内容,再将指针前移
p=p.next;
if(p.next!=null){//之前队列中只添加了链表的头!后面需要继续添加链表后面的部分!
queue.add(p.next);
}
}
return dummyHead.next;
}
}
思路:
-
在一堆元素中找出前k个:优先队列!
-
头节点的作用:防止真实的头节点为空;便于节点的操作,统一了空表和非空表的操作。
-
优先队列:添加:add,查看并移除队首:poll,大小:size
初始化:PriorityQueue() 使用默认的初始容量(11)创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue(Collection<? extends E> c) 创建包含指定 collection 中元素的 PriorityQueue。
PriorityQueue(int initialCapacity) 使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。
PriorityQueue(int initialCapacity, Comparator<? super E> comparator) 使用指定的初始容量创建一个 PriorityQueue,并根据指定的比较器对元素进行排序。
题解二 递归
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length==0){
return null;
}
if(lists.length==1){
return lists[0];
}
if(lists.length==2){
return mergeTwoLists(lists[0],lists[1]);
}
int len=lists.length/2;
ListNode[] l1=new ListNode[len];
ListNode[] l2=new ListNode[lists.length-len];
for(int i=0;i<len;i++){
l1[i]=lists[i];
}
for(int i=0,j=len;j<lists.length;i++,j++){
l2[i]=lists[j];
}
return mergeTwoLists(mergeKLists(l1),mergeKLists(l2));
}
private ListNode mergeTwoLists(ListNode node1,ListNode node2){
if(node1==null){
return node2;
}
if(node2==null){
return node1;
}
ListNode dummyHead=new ListNode(0);
if(node1.val<=node2.val){
dummyHead.next=node1;
node1.next=mergeTwoLists(node1.next,node2);//node1的下一个原本指向本链表的下一个,这样的递归使其指向
}else{
dummyHead.next=node2;
node2.next=mergeTwoLists(node1,node2.next);
}
return dummyHead.next;
}
}
思路:
- 合并两个lists的思路和21是一样的。先写终止条件,再设置虚拟头节点,比较两个节点的大小,小节点的下一个指针指向整个递归体。
- 再将整个数组分成两半,递归调用merge函数。
- 注意在主函数返回时mergeTwoLists中,要调用主函数。多看看这种题。