合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/merge-k-sorted-lists
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这道题有三种解法,
1,逐个合并队列,队列1+队列2=sum1,sum1+队列3,=sum2,。。。直到合并完毕,这种算法效率最低,为O(nk*k)
2,使用优先队列,
把n个队列的头加入一个优先队列,每次取出第一个元素e,肯定是当前最小的元素,
取出后,如果e.next!=null,把e.next加入队列中,
直到队列为空,合并完毕
复杂度为:O(kn×logk)。
3,把队列两两合并,然后对合并后的结果进行两两合并,直到和为一个,复杂度为: O(kn \times \log k)O(kn×logk)
详细解释,见leetcode官方
代码如下:实现了1,和2,
public class Solution15 {
public static void main(String[] args) {
Solution15 so3 = new Solution15();
int[][] inits = new int[][] { { 1, 2, 2 }, { 1, 1, 2 } };
ListNode[] lists = so3.getInitList(inits);
ListNode node = so3.mergeKLists(lists);
do {
System.out.print(node.val + ",");
node = node.next;
} while (node != null);
System.out.println();
lists = so3.getInitList(inits);
node = so3.mergeKLists2(lists);
do {
System.out.print(node.val + ",");
node = node.next;
} while (node != null);
}
/**
* 常规算法,逐个比对,插入每个队列
*
* @param lists
* @return
*/
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) {
return null;
}
if (lists.length == 1) {
return lists[0];
}
ListNode head = lists[0];
int headi = 0;
// 计算head的val
for (int i = 0; i < lists.length; i++) {
if (lists[i] == null) {
continue;
}
if (head == null) {
head = lists[i];
headi = i;
}
if (head.val > lists[i].val) {
lists[headi] = head;
head = lists[i];
headi = i;
}
}
lists[headi] = null;
ListNode n = head;
ListNode nx = null;
for (int i = 0; i < lists.length; i++) {
ListNode n2 = lists[i];
if (n2 == null) {
continue;
}
// 从头开始合并
n = head;
while (n.next != null && n2 != null) {
// 如果n2,比n小,说明需要排在n前面
if (n.next.val > n2.val) {
nx = n.next;
n.next = n2;
n2 = n2.next;
n.next.next = nx;
} else {
n = n.next;// 说明主队列太大,需要往后移动
}
}
if (n2 != null) {// 如果最后n2不为空,把n2加到队尾
n.next = n2;
}
}
return head;
}
/**
* 把n个队列的头加入一个优先队列,每次取出第一个元素e,肯定是当前最小的元素,
* 取出后,如果e.next!=null,把e.next加入队列中,
* 直到队列为空,合并完毕
*
* @param lists
* @return
*/
public ListNode mergeKLists2(ListNode[] lists) {
if (lists == null || lists.length == 0) {
return null;
}
if (lists.length == 1) {
return lists[0];
}
Queue<ListNode> pqe = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
if (o1 == null) {// 空最大,放后面
return 1;
}
if (o2 == null) {
return -1;
}
if (o1.val > o2.val) {
return 1;// 前面的大
}
return -1;
}
});
for (int i = 0; i < lists.length; i++) {
if (lists[i] != null) {
pqe.add(lists[i]);
}
}
ListNode nx = null;
ListNode head = pqe.poll();
if (head == null) {
return null;
}
if (head.next != null) {
pqe.add(head.next);
}
boolean hasMore = true;// 判断是否还有更多的数据需要加入队列
nx = pqe.poll();
ListNode n = head;
while (nx != null) {
n.next = nx;
n = n.next;
if (nx.next != null) {
pqe.add(nx.next);
}
nx = pqe.poll();
}
return head;
}
ListNode[] getInitList(int[][] towIs) {
ListNode[] nodes = new ListNode[towIs.length];
for (int j = 0; j < towIs.length; j++) {
int[] ones = towIs[j];
if (ones == null || ones.length == 0) {
continue;
}
ListNode n = new ListNode(ones[0]);
nodes[j] = n;
for (int i = 1; i < ones.length; i++) {
n.next = new ListNode(ones[i]);
n = n.next;
}
}
return nodes;
}
}