23. 合并K个升序链表
题目链接
暴力合并
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
ListNode head = new ListNode();
ListNode p = head;
while(true){
boolean hasNum = false;
int minN = 10001, minI = -1;
for(int i = 0; i < lists.length; i++)
if(lists[i] != null){
hasNum = true;
if(lists[i].val < minN){
minN = lists[i].val;
minI = i;
}
}
if(!hasNum) break;
p.next = new ListNode(lists[minI].val);
p = p.next;
lists[minI] = lists[minI].next;
}
return head.next;
}
}
- 每次遍历所有剩余的数,找最小的
- 时间复杂度为O(k2n),空间复杂度为O(1)
优先队列
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
Queue<Integer> q = new PriorityQueue<>();
for(int i = 0; i < lists.length; i++){
while(lists[i] != null){
q.add(lists[i].val);
lists[i] = lists[i].next;
}
}
ListNode head = new ListNode();
ListNode p = head;
while(!q.isEmpty()){
p.next = new ListNode(q.poll());
p = p.next;
}
return head.next;
}
}
- 把所有数塞到优先队列里,再取出来
- 时间复杂度为O(kn·logkn),空间复杂度为O(kn)
- 如果先把每个链表的第一个加入优先队列,取出后再放入第二个,时间和空间都能有所优化,但是写起来太麻烦了
分治合并
class Solution {
public ListNode mergeKLists(ListNode[] lists){
return merge(lists, 0, lists.length - 1);
}
private ListNode merge(ListNode[] lists, int l, int r){
if (l == r) return lists[l];
if (l > r) return null;
int mid = (l + r) >> 1;
return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r));
}
private ListNode mergeTwoLists(ListNode l1, ListNode l2){
ListNode head = new ListNode();
ListNode p = head;
while(l1 != null && l2 != null){
p.next = new ListNode();
p = p.next;
if(l1.val < l2.val){
p.val = l1.val;
l1 = l1.next;
} else{
p.val = l2.val;
l2 = l2.next;
}
}
p.next = l1 == null? l2: l1;
return head.next;
}
}
- 利用之前的合并两个有序链表,按照分治排序的思想,二分后两两合并
- 时间复杂度为O(kn·logk),空间复杂度为O(logk)(递归的栈空间)