Merge k Sorted Lists-LeetCode

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

题目描述:归并排序k个有序单链表。(感觉LeetCode说到排序默认即是自然会顺序,数字递增,字母按顺序)

题目思路:

【超时思路】先说一个由二路归并得来的思维简单、看似取巧实则复杂度奇高的方法:直接k路归并。

1.内循环:
在lists指向的k个链表元素之间选出一个最小的lists[i],链接到最终要输出的链表上去,再将
lists[i]指向最小元素的下一个节点。

2.外循环:

循环上述过程直到lists都为空。

复杂度分析:假设有n个长度都为m的有序链表在归并,那么总的比较次数是多少呢?取出一个元素要比较n次,那么总共要经历O(n*n*m)次比较才可以完全归并。这复杂度交LeetCode上,妥妥的超时了。

超时代码:

class ListNode {
	int val;
	ListNode next;
	ListNode(int x) { val = x; }
}
public class Solution {
	
	/** 思路简单,但是最坏复杂度很高的算法。比如n个单链表都只有一个元素,用该方法归并却需要n*n次大小比较,复杂度太高了
	 * @param lists
	 * @return
	 */
	public ListNode mergeKLists(ListNode[] lists) {
		ListNode result=new ListNode(0),p=result;
		int k=0,min=0;
		while(true){
			min=Integer.MAX_VALUE;
			k=-1;
			for(int i=0;i<lists.length;i++){
				//每次都从lists[]所指向的头里挑出来一个最小的,加入有序单链表
				if(lists[i]!=null && min>=lists[i].val){
					//记录最小值和index位置
					min=lists[i].val;
					k=i;
				}
			}
			if(k==-1){
				//若在本轮查找中,没有进入比较环节,则所有链表都到头了,退出循环返回
				p.next=null;
				break;
			}else{
				p=p.next=lists[k];
				lists[k]=lists[k].next;
			}
		}
		return result.next;
	}
}

【AC思路】AC代码的思路本质也是建立在二路归并排序上的,即将lists的链表两两两路归并,最后得到最后的一路链表输出即可。粗略的看,整体复杂度最大不超过O(n2logn)。

import java.lang.Math;

class ListNode {
	int val;
	ListNode next;
	ListNode(int x) { val = x; }
}

public class Solution {
	public ListNode mergeKLists(ListNode[] lists) {
		if(lists.length>0){	//如果lists中的元素数在1一下,就不用归并了,直接输出就好
			int Niterator=(int)Math.ceil(Math.log(lists.length)/Math.log(2));
			//在lists中使用二路归并,要归并多少层(8进4视为一层,4进2视为一层),做法就是log2(lists.length)再向上取整就行了
			for(int i=1;i<=Niterator;i++){
				int interval=(int)Math.pow(2, i);	//对于不同的归并层,计算每个归并组的间隔,最底层2,上一层4,再上一层8,就这么来
				for(int j=0;j+interval/2<lists.length;j+=interval){
					lists[j]=mergeTwoLists(lists[j],lists[j+interval/2]);
					//在每一组内做二路归并,把结果给到这组的首个位置上保存,j+interval/2这个值的由来大家画个满二叉树体会一下就好了
				}
			}
			return lists[0];
		}else return null;	
	}

	public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
		//二路归并,O(N)复杂度,太简单啦
		ListNode result=new ListNode(0),p=result,p1=l1,p2=l2;
		while(p1!=null&&p2!=null){
			if(p1.val<p2.val){
				p=p.next=p1;
				p1=p1.next;
			}else{
				p=p.next=p2;
				p2=p2.next;
			}
		}
		p.next=(p1==null?p2:p1);	//一个链表先耗尽,就把另一个接到已有序的链表末位
		return result.next;
	}
}


public class Main{  
	public static void main(String[] args){  

		/*Scanner in=new Scanner(System.in); 
        String target=in.nextLine();*/  

		ListNode[] lists=new ListNode[0];

		for(int j=0;j<lists.length;j++){
			lists[j]=new ListNode(1);
			ListNode temp=lists[j];  
			for(int i=2;i<=6;i++){  
				temp.next=new ListNode(i);  
				temp=temp.next;  
			}  
			temp.next=null;
		}



		long startTime=System.currentTimeMillis();  
		Solution find=new Solution();  
		ListNode temp=find.mergeKLists(lists);  

		long endTime=System.currentTimeMillis();  
		long excTime=(long)(endTime-startTime);  
		System.out.println("执行时间:"+excTime+"ms");

		for(int i=0;temp!=null;i++){  
			System.out.println(temp.val);  
			temp=temp.next;
		} 
	}  
}  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值