Merge k Sorted Lists

本文探讨了如何合并K个已排序的链表并返回一个单一的排序链表,介绍了几种不同的解决方案,包括直接比较法、分治法及使用优先队列的方法,并分析了各自的复杂度。

题目描述:
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

一开始就是用Merge Two Sorted Lists的做法,每次用findMinIndex来找到list中最小的node,加入到head中,时间复杂度为O(nk),超时,代码如下:

public int findMinIndex(ListNode[] list){
    int minIndex=-1,minValue=Integer.MAX_VALUE,n=list.length;
    for(int i=0;i<n;i++) {
        if(list[i]!=null){
            if(list[i].val<minValue){
                minValue=list[i].val;
                minIndex=i;
            }
        }
    }
    return minIndex;
}

public ListNode mergeKLists(ListNode[] lists) {
    ListNode head=null,tail=null;
    int minIndex;
    while((minIndex=findMinIndex(lists))!=-1){
        ListNode newNode=new ListNode(lists[minIndex].val);
        if(head==null){
            head=newNode;
            tail=newNode;
        }else{
            tail.next=newNode;
            tail=newNode;
        }
        lists[minIndex]=lists[minIndex].next;
    }
    return head;
}

后来想了一下,这个算法的毛病是如果list[i]==null,list[i]还要不停的参与比较,于是我就想将List转换成Set,每次当list[i]==null的时候将list[i]从Set中除去。但是这样又出现了一个毛病,用iterator遍历set中每一个ListNode的时候就不好改变listNode的值了。

这个题的正确解法是分治法:

public ListNode mergeKLists(ListNode[] lists) {
	if(lists==null||lists.length==0)
        return null;
    return linkedListSort(lists,0,lists.length-1);
}	

public ListNode linkedListSort(ListNode[] lists,int left,int right){
	if(left == right){
		return lists[left];
	}
	int mid = (left + right) / 2;
	ListNode leftList = linkedListSort(lists,left,mid);
	ListNode rightlist = linkedListSort(lists,mid+1,right);
	ListNode node = mergeTwoLists(leftList,rightlist);
	return node;
}

public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
	ListNode listNode = null;
	if(l1==null)
		return l2;
	if(l2==null)
		return l1;
	if(l1.val<l2.val){
		listNode = l1;
		l1 = l1.next;
	}else {
		listNode = l2;
		l2 = l2.next;
	}
	ListNode p = listNode;
	while(l1!=null&&l2!=null){
		if(l1.val<=l2.val){
			p.next = l1;
			l1 = l1.next;
			p = p.next;
		}else{
			p.next = l2;
			l2 = l2.next;
			p = p.next;
		}
	}
	if(l1==null){
		p.next = l2;
	}else{
		p.next = l1;
	}
    return listNode;
}

这个题还可以用堆算法来解决,但是这样要维护一个优先队列,优先队列是用最小堆来实现的,每次动态增加或者删除队列中的元素,始终保持小顶堆。

public ListNode mergeKLists(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.length;i++)
    {
        ListNode node = lists[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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值