Description
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
分析
归并多个排序的链表为一个有序链表。这是继merge two sorted list之后的一个扩展,早几天面试的时候面试官直接要我在电脑上OJ这题。
对于两个已经排序的链表,我们知道最小值定在两个头节点,然后我们通过比较获得最小节点之后,移动指向最小节点的指针,那么下一个最小节点还是在两个头节点中。
将k个已排序的链表归并为一个有序链表,关键就是在k个链表中找到最小的节点,然后移除该节点并将其插入到输出链表的尾部,继续查找下一个最小节点,直到k个链表都为空。那么如何寻找最小节点呢?k个链表都是为有序的链表,那么每个链表中的最小节点在链表的头节点,所有链表中的最小节点就在k个链表的头节点中找,当移除最小节点后,该链表会有一个新的头节点,最小值还是在k个链表的头节点中找。如此重复,直到k个链表都为空,我们就能得到一个排序的链表了。
那么如何快速找到这个最小节点呢,寻找最小值,那用堆啊。建立一个初始大小为k的堆,将k个链表的头节点放入其中。接着从堆中取出最小节点,添加到输出链表尾部,再将该最小节点的下一个节点插入堆中,若下一个节点为空,则说明已经到达链表尾部,该链表已经无需再处理。重复上述过程,直至堆为空,k个有序链表就归并为一个有序链表了。
数据结构采用PriorityQueue,为节点建立一个比较器。
若节点总数为n,堆的大小为k,对堆的插入或取出操作需要O(logk),那么这个算法的时间复杂度为O(nlogk)。空间复杂度为O(k)。
Code
使用heap
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/
public class Solution {
public class NodeCompare implements Comparator<ListNode>{
public int compare(ListNode n1,ListNode n2){
return n1.val-n2.val;
}
}
public ListNode mergeKLists(ListNode[] lists) {
int k=lists.length;//heap size
ListNode tmpHead=new ListNode(-1);//fake head
ListNode cur=tmpHead;//current pointer
if(k==0)return tmpHead.next;
if(k==1)return tmpHead.next=lists[0];
else{
PriorityQueue<ListNode> heap=new PriorityQueue<ListNode>(k,new NodeCompare());
// k size heap, natrual order, aka min heap
//initialize heap, the min node is in the head of all list
for(int i=0;i<k;i++){
if(lists[i]!=null){
heap.offer(lists[i]);
}
}
//find min till empty
while(!heap.isEmpty()){
ListNode min=heap.poll();//find min node
cur.next=min;//append to the output list
cur=cur.next;//cur move a step
if(min.next!=null){//if this list is empty, move on
heap.offer(min.next);//insert next node
}
//continue
}
return tmpHead.next;
}
}
}