题目及测试
package pid023;
/* 合并K个元素的有序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。
示例:
输入:
[
1->4->5,
1->3->4,
2->6
]
输出: 1->1->2->3->4->4->5->6
*/
public class main {
public static void main(String[] args) {
LinkList a=new LinkList(1);
a.addLast(4);
a.addLast(5);
a.printList();
LinkList b=new LinkList(1);
b.addLast(3);
b.addLast(4);
b.printList();
LinkList c=new LinkList(2);
c.addLast(6);
c.printList();
ListNode[] listNodes=new ListNode[]{a.first,b.first,c.first};
test(listNodes);
}
private static void test(ListNode[] ito) {
Solution solution = new Solution();
ListNode rtn;
long begin = System.currentTimeMillis();
System.out.println();
//开始时打印数组
rtn=solution.mergeKLists(ito);//执行程序
long end = System.currentTimeMillis();
System.out.println("rtn=");
rtn.printNodeToEnd();
//System.out.println(":rtn" );
//System.out.print(rtn);
System.out.println();
System.out.println("耗时:" + (end - begin) + "ms");
System.out.println("-------------------");
}
}
解法1(成功,471ms,极慢)
比较 k个节点(每个链表的首节点),获得最小值的节点。
将选中的节点接在最终有序链表的后面。
时间复杂度: O(kN),其中 k是链表的数目。
package pid023;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import pid116.Node;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
int length=lists.length;
if(length==0){
return null;
}
if(length==1){
return lists[0];
}
ListNode first=new ListNode(0);
ListNode now=first;
while(true){
int min=Integer.MAX_VALUE;
int minIndex=-1;
for(int i=0;i<length;i++){
if(lists[i]!=null&&min>=lists[i].val){
min=lists[i].val;
minIndex=i;
}
}
if(minIndex==-1){
break;
}else{
now.next=lists[minIndex];
now=now.next;
lists[minIndex]=lists[minIndex].next;
}
}
return first.next;
}
}
解法2(别人的)
使用优先级队列,PriorityQueue
时间复杂度:O(n∗log(k)),n
是所有链表中元素的总和,k
是链表个数。
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) return null;
PriorityQueue<ListNode> queue = new PriorityQueue<>(lists.length, new Comparator<ListNode>() {
@Override
public int compare(ListNode o1, ListNode o2) {
if (o1.val < o2.val) return -1;
else if (o1.val == o2.val) return 0;
else return 1;
}
});
ListNode dummy = new ListNode(0);
ListNode p = dummy;
for (ListNode node : lists) {
if (node != null) queue.add(node);
}
while (!queue.isEmpty()) {
p.next = queue.poll();
p = p.next;
if (p.next != null) queue.add(p.next);
}
return dummy.next;
}
}
解法3(成功,9ms,较慢)
优先队列能传入的参数有index,ListNode,val,可以只传入ListNode,因为它包含了val,并且还有next,能够定位当前节点和下一个节点。如果传入index,可以用Pair<val,index>。
public ListNode mergeKLists(ListNode[] lists) {
int length=lists.length;
if(length==0){
return null;
}
if(length==1){
return lists[0];
}
ListNode first=new ListNode(0);
ListNode now=first;
Comparator<Pair<Integer, Integer>> compartor = new Comparator<Pair<Integer, Integer>>() {
@Override
public int compare(Pair<Integer, Integer> o1, Pair<Integer, Integer> o2) {
return o1.getKey() - o2.getKey();
}
};
PriorityQueue<Pair<Integer, Integer>> queue = new PriorityQueue<Pair<Integer,Integer>>(compartor);
for(int i=0;i<length;i++) {
if(lists[i] != null) {
queue.add(new Pair<Integer, Integer>(lists[i].val, i));
}
}
while(true){
if(queue.isEmpty()) {
break;
}else {
Pair<Integer, Integer> pair = queue.poll();
int index = pair.getValue();
now.next = lists[index];
now = now.next;
lists[index] = lists[index].next;
if(lists[index] != null) {
queue.add(new Pair<Integer, Integer>(lists[index].val, index));
}
}
}
return first.next;
}