23. Merge k Sorted Lists

输入:k个有序链表lists
输出:一个有序链表
规则:将这个k个有序链表合并成一个有序链表
分析:在链表中合并两个有序链表为一个有序链表是基本功。最开始的直觉是我们可以将lists[0]和lists[1]合并得到 result,result再和lists[2]合并,一直 到最后合并完成。这个每个节点 都要和其他链表中的一个节点比较,所以时间复杂度是O(k*n)。n是所有节点的个数总和。

	public ListNode mergeKLists(ListNode[] lists) {
		ListNode mergeHead = new ListNode(0);
		ListNode node = mergeHead;
		while(true){
			ListNode minHead = null;
            int idx = -1;
			for (int i=0;i<lists.length;i++) {
				if (lists[i] != null) {
					if(minHead == null || minHead.val> lists[i].val){
						minHead = lists[i];
                        idx = i;
					}
				}
			}
			if(minHead==null){
				break;
			}
            lists[idx] = lists[idx].next;
			node.next = new ListNode(minHead.val);
			node = node.next;
		}
		return mergeHead.next;
    }

分析2:可以使用堆排序解决上面的比较问题。在堆中维护的是每个链表 表头元素。移除最小的节点,插入链表中的下一个节点。时间复杂度O(nlogk)。

	public ListNode mergeKLists(ListNode[] lists) {
        ListNode dummy =  new ListNode(-1);
        ListNode current = dummy;
        PriorityQueue<ListNode> heap = new PriorityQueue<ListNode>(new Comparator<ListNode>(){
            public int compare(ListNode i1,ListNode i2){
                return i1.val-i2.val;
            }
        });
        
        //把头节点放进去
        for(ListNode node: lists){
            if(node!=null){
                heap.offer(node);
            }           
        }
        
        while(!heap.isEmpty()){
            ListNode node = heap.poll();
            if(node.next != null){
                heap.offer(node.next);
                
            } 
            current.next = node;
            current = current.next;
        }
        return dummy.next;
    }

分析3:使用分治法。先解决lists[0]和lists[1],lists[2]和lists[3]…,合并完成只剩下 k 2 \dfrac{k}{2} 2k。下一轮解决lists[0]和lists[2],lists[4]和lists[6]…,合并完成剩下 k 4 \dfrac{k}{4} 4k…一直到最后只剩下lists[0],就是结果。

	public ListNode mergeKLists(ListNode[] lists) {
        for(int interval =1 ;interval<lists.length; interval=interval*2){
            for(int j = 0;j+interval<lists.length;j = j + 2*interval){
                lists[j] = mergeTwoLists(lists[j],lists[j+interval]);
            }
        }
        return lists.length>0?lists[0]:null;
    }
    
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(-1);
        ListNode currentNode = dummy;
        while(l1!=null  && l2!=null){
            if(l1.val > l2.val){
                currentNode.next = l2;
                l2 = l2.next;
            }else{
                currentNode.next = l1;
                l1 = l1.next;
            }
            currentNode = currentNode.next;
        }
        
        while(l1!=null){
            currentNode.next = l1;
            l1 = l1.next;
            currentNode = currentNode.next;
        }
        while(l2!=null){
            currentNode.next = l2;
            l2 = l2.next;
            currentNode = currentNode.next;
        }
        return dummy.next;
    }

复杂度分析。最外层循环有 l o g 2 k log_2^k log2k次。mergeTwoLists函数的时间复杂度是n=两个列表节点个数的和。最后合起来是O(nlogk)。这里的n是所有链表节点个数和。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值