思路
1.首先想到了归并排序的合并操作:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if(lists.length == 0)
return null;
return mergeList(lists)[0];
}
public ListNode[] mergeList(ListNode[] lists) {
//思路:想到了归并排序分治后两辆合并合并 NlogN
//还可以扔到大根堆然后
if (lists.length == 1)
return lists;
ArrayList<ListNode> listNodes = new ArrayList<>();
for (int i = 0; i < lists.length - 1; i = i + 2) {
ListNode merge = merge(lists[i], lists[i + 1]);
listNodes.add(merge);
}
if(lists.length % 2 > 0)
listNodes.add(lists[lists.length - 1]);
return mergeList(listNodes.toArray(new ListNode[listNodes.size()]));
}
public ListNode merge(ListNode listNode1, ListNode listNode2) {
ListNode cur = new ListNode();
ListNode head = cur;
while (listNode1 != null && listNode2 != null) {
if (listNode1.val >= listNode2.val) {
cur.next = listNode2;
listNode2 = listNode2.next;
} else {
cur.next = listNode1;
listNode1 = listNode1.next;
}
cur = cur.next;
}
if (listNode1 != null && listNode2 == null){
cur.next = listNode1;
}
if (listNode2 != null && listNode1 == null){
cur.next = listNode2;
}
return head.next;
}
}
优化版本的分治
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int len = lists.length;
if (len == 0) {
return null;
}
return mergeKLists(lists, 0, len - 1);
}
public ListNode mergeKLists(ListNode[] lists, int left, int right) {
if (left == right) {
return lists[left];
}
int mid = left + (right - left) / 2;
ListNode list1 = mergeKLists(lists, left, mid);
ListNode list2 = mergeKLists(lists, mid + 1, right);
return mergeTwoSortLinkedList(list1, list2);
}
public ListNode mergeTwoSortLinkedList(ListNode listNode1, ListNode listNode2) {
ListNode cur = new ListNode();
ListNode head = cur;
while (listNode1 != null && listNode2 != null) {
if (listNode1.val >= listNode2.val) {
cur.next = listNode2;
listNode2 = listNode2.next;
} else {
cur.next = listNode1;
listNode1 = listNode1.next;
}
cur = cur.next;
}
if (listNode1 != null && listNode2 == null){
cur.next = listNode1;
}
if (listNode2 != null && listNode1 == null){
cur.next = listNode2;
}
return head.next;
}
}
优先队列法
因为链表都有序了,加入头节点构成小根堆,每次出队根节点然后入队next节点,保证堆中始终存在当前最小值
import java.util.Comparator;
import java.util.PriorityQueue;
public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int len = lists.length;
if (len == 0) {
return null;
}
PriorityQueue<ListNode> minHeap = new PriorityQueue<>(len, Comparator.comparingInt(o -> o.val));
for (ListNode head : lists) {
if (head != null) {
minHeap.offer(head);
}
}
ListNode dummyNode = new ListNode(-1);
ListNode curNode = dummyNode;
while (!minHeap.isEmpty()) {
// 注意:这里我们选择的操作是先从优先队列里拿出最小的元素,然后再添加
// 事实上,如果优先队列有提供 replace 操作,应该优先选择 replace
ListNode top = minHeap.poll();
curNode.next = top;
curNode = curNode.next;
if (top.next != null) {
minHeap.offer(top.next);
}
}
return dummyNode.next;
}
}