算法 -- 合并K个升序链表
原题:
23. 合并K个升序链表
困难
2.4K
相关企业
给你一个链表数组,每个链表都已经按升序排列。
请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 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
解法:
- 暴力遍历加合并链表:两个两个合并,傻办法但有效
上代码
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode res = null;
for(int i=0;i<lists.length;i++){
res = mergeL(res,lists[i]);
}
return res;
}
public ListNode mergeL(ListNode list1, ListNode list2){
if(list1 == null || list2 == null){
return list1 != null ? list1 :list2;
}
ListNode head = new ListNode(0);
ListNode tail = head, p1 = list1,p2 = list2;
while(p1 != null && p2 != null){
if(p1.val <= p2.val){
tail.next = p1;
p1 = p1.next;
}else{
tail.next = p2;
p2 = p2.next;
}
tail = tail.next;
}
tail.next = p1 != null ? p1:p2;
return head.next;
}
}
- 大佬优雅版
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0) return null;
ListNode[] list1 = new ListNode[lists.length - 1];
System.arraycopy(lists, 1, list1, 0, lists.length - 1);
return mergeTwoLists(lists[0], mergeKLists(list1));
}
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
if(list1 == null) return list2;
if(list2 == null) return list1;
ListNode head = list1.val <= list2.val ? list1 : list2;
head.next = mergeTwoLists(head.next, list1.val <= list2.val ? list2 : list1);
return head;
}
}
2.使用优先队列
由于优先队列可以边插变排序,包括链表,所以可以用该队列替换合并链表的操作
上代码:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode res = new ListNode(0);
ListNode cur = res;
PriorityQueue<ListNode> pq = new PriorityQueue<>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
return o1.val - o2.val;
}
});
for(ListNode list: lists){
if(list == null)
continue;
pq.add(list);
}
while(!pq.isEmpty()){
ListNode nex = pq.poll();
cur.next = nex;
cur = cur.next;
if(nex.next != null){
pq.add(nex.next);
}
}
return res.next;
}
}
- 分支合并
就是在第一个方法基础上的优化,即一次循环两两合并,合并一半的链表长度
- 可以使用递归的方式来分治
代码:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int n = lists.length;
if(n == 0)return null;
if(n == 1)return lists[0];
if(n == 2)return mergeL(lists[0],lists[1]);
int mid = n/2;
ListNode[] resList1 = new ListNode[mid];
ListNode[] resList2 = new ListNode[n-mid];
for(int i=0;i<mid;i++){
resList1[i] = lists[i];
}
for(int i = mid,j=0;i<n;i++,j++){
resList2[j] = lists[i];
}
return mergeL(mergeKLists(resList1),mergeKLists(resList2));
}
public ListNode mergeL(ListNode list1, ListNode list2){
if(list1 == null || list2 == null){
return list1 != null ? list1 :list2;
}
ListNode head = new ListNode(0);
ListNode tail = head, p1 = list1,p2 = list2;
while(p1 != null && p2 != null){
if(p1.val <= p2.val){
tail.next = p1;
p1 = p1.next;
}else{
tail.next = p2;
p2 = p2.next;
}
tail = tail.next;
}
tail.next = p1 != null ? p1:p2;
return head.next;
}
}