题目
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
合并n个有序链表
解法一
可以采用分治法。先把大任务先分成两个子任务,然后递归求子任务,最后回溯回来。有点类似先分后合。这个题目也可以采用这样的算法。即将k个链表平均分成两份,继续划分,直到左边界和右边界相等,返回这个链表,也就是最后会分成剩下一个链表。 然后每两个链表合并,合并之后再合并,回溯回来。最后合并成一个链表。完成。代码如下。(表达不清楚,还请见谅)其中merge是合并两个链表的算法。
public ListNode mergeKLists(ListNode[] lists) {
if(lists == null || lists.length==0) return null;
return partion(lists,0,lists.length-1);
}
public static ListNode partion(ListNode[] lists,int l,int r){
if(l<r){
int m = (l+r)/2;
ListNode l1 = partion(lists,l,m);
ListNode l2 = partion(lists,m+1,r);
return merge(l1,l2);
} else{
return lists[l];
}
}
public static ListNode merge(ListNode l1,ListNode l2){
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val < l2.val){
l1.next = merge(l1.next,l2);
return l1;
}else{
l2.next = merge(l1,l2.next);
return l2;
}
}
解法二
使用优先队列。优先对列底层默认使用最小堆实现的。即从对堆里面取一个数取到的是最小的数。因此我们可以把k个节点放入优先队列中,每次从中取最小的一个。取完再把取出节点的下一节点放进去。因为链表是有序的,因此当优先队列为空时,所有列表都已经遍历完了。
public ListNode mergeKLists(ArrayList<ListNode> lists) {
PriorityQueue<ListNode> heap = new PriorityQueue<ListNode>(10,new Comparator<ListNode>(){
@Override
public int compare(ListNode n1, ListNode n2)
{
return n1.val-n2.val;
}
});
for(int i=0;i<lists.size();i++)
{
ListNode node = lists.get(i);
if(node!=null)
{
heap.offer(node);
}
}
ListNode head = null;
ListNode pre = head;
while(heap.size()>0)
{
ListNode cur = heap.poll();
if(head == null)
{
head = cur;
pre = head;
}
else
{
pre.next = cur;
}
pre = cur;
if(cur.next!=null)
heap.offer(cur.next);
}
return head;
}