编程之美2.5 寻找最大的K个数

//题目:寻找数组中最大的k个数
//解法1:使用快排或选择排序,快排完成的复杂度O(NlogN),选择排序O(N*K)
public class Main {  
	  
    public static void main(String[] args) throws Exception {  
    	int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
    	int[] result2 = findMaxKNum2(new int[]{3,4,5,3,2,1,6,8},3);
    	for(int i = 0;i<result1.length;i++){
    		System.out.print(result1[i]+" ");
    	}
    	System.out.println();
    	for(int i = 0;i<result2.length;i++){
    		System.out.print(result2[i]+" ");
    	}
    }  
  
    //选择排序O(N*K) 因为只需要进行K趟排序
    public static int[] findMaxKNum1(int[] input, int k) throws Exception {  
    	for(int i = 0;i<k;i++){
    		int index = i;
    		for(int j = i+1;j<input.length;j++){
    			if(input[index]<input[j]){
    				index = j;
    			}
    		}
    		if(index!=i){
    			int temp = input[index];
    			input[index] = input[i];
    			input[i] = temp;
    		}
    	}
    	int[] result = new int[k];
    	for(int i = 0;i<k;i++){
    		result[i] = input[i];
    	}
    	return result;
    }  
    
    //快速排序O(N*logN)需要全部排序完毕才能选择最大的k个
    public static int[] findMaxKNum2(int[] input, int k) throws Exception {  
    	sort(input, 0, input.length-1);
    	int[] result = new int[k];
    	for(int i = 0;i<k;i++){
    		result[i] = input[i];
    	}
    	return result;
    }
    public static void sort(int[] input, int low, int high){
    	if(low<high){
    		int mid = partition(input, low, high);
    		sort(input,low,mid-1);
    		sort(input,mid+1,high);
    	}
    }
    public static int partition(int[] input, int low, int high){
    	int temp = input[low];
    	while(low<high){
    		while(low<high && temp>=input[high]){
    			high--;
    		}
    		input[low] = input[high];
    		while(low<high && temp<=input[low]){
    			low++;
    		}
    		input[high] = input[low];
    	}
    	input[low] = temp;
    	return low;
    }
  
}

//解法2:采用类似于快排的方式,每次返回mid点,如果mid为k则直接取前k个元素,否则根据mid与k的比较情况决定递归的方向  O(N*logK)
public class Main {  
	  
    public static void main(String[] args) throws Exception {  
    	int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
    	for(int i = 0;i<result1.length;i++){
    		System.out.print(result1[i]+" ");
    	}
    	System.out.println();
    }  
  
    public static int[] findMaxKNum1(int[] input, int k) throws Exception {  
    	int mid = partition(input, 0, input.length-1);
    	while(mid!=k){
    		if(mid<k){
    			mid = partition(input,mid+1,input.length-1);
    		}else{
    			mid = partition(input,0,mid-1);
    		}
    	}
    	int[] result = new int[k];
    	for(int i = 0;i<k;i++){
    		result[i] = input[i];
    	}
    	return result;
    }
    
    public static int partition(int[] input, int low, int high){
    	int temp = input[low];
    	while(low<high){
    		while(low<high && temp>=input[high]){
    			high--;
    		}
    		input[low] = input[high];
    		while(low<high && temp<=input[low]){
    			low++;
    		}
    		input[high] = input[low];
    	}
    	input[low] = temp;
    	return low;
    }
  
}

//解法3:建立一个大小为K的堆,每次将这个堆中的元素进行排序,将之后的元素与堆中最小的元素进行比较,如果比堆中元素大,则将其加入堆中
public class Main {  
	  
    public static void main(String[] args) throws Exception {  
    	int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
    	for(int i = 0;i<result1.length;i++){
    		System.out.print(result1[i]+" ");
    	}
    	System.out.println();
    }  
  
    public static int[] findMaxKNum1(int[] input, int k) throws Exception {  
    	buildMinHeap(input,k);
    	for(int i = k;i<input.length;i++){
    		if(input[0] < input[i]){
    			input[0] = input[i];
    			adjustDown(input,0,k);
    		}
    	}
    	int[] result = new int[k];
    	for(int i = 0;i<k;i++){
    		result[i] = input[i];
    	}
    	return result;
    }
    
    public static void buildMinHeap(int[] input, int len){
    	for(int i = len/2-1;i>=0;i--){
    		adjustDown(input,i,len);
    	}
    }
    
    public static void adjustDown(int[] input, int k, int len){
    	int temp = input[k];
    	for(int i = k*2+1;i<len-1;i = i*2){
    		if(i+1<=len-1 && input[i+1]<input[i]){
    			i = i+1;
    		}
    		if(input[k]<input[i]){
    			break;
    		}
    		input[k] = input[i];
    		k = i;
    	}
    	input[k] = temp;
    }
  
}

//解法4:采用二分法,每次找到最大最小值中间的元素,看比这个元素大的元素个数是否为K,如果为K,就找比这个数大的数返回即可O(N*logN)
public class Main {  
	  
    public static void main(String[] args) throws Exception {  
    	int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
    	for(int i = 0;i<result1.length;i++){
    		System.out.print(result1[i]+" ");
    	}
    	System.out.println();
    }  
  
    public static int[] findMaxKNum1(int[] input, int k) throws Exception {  
    	int maxValue = findMax(input);
    	int minValue = findMin(input);
    	int kValue = findKValue(input,k,minValue,maxValue);
    	int[] result = new int[k];
    	int temp = 0;
    	for(int i = 0;i<input.length;i++){
    		if(input[i]>kValue){
    			result[temp] = input[i];
    			temp++;
    		}
    	}
    	return result;
    }
    
    //找到数组中最大的数
    public static int findMax(int[] input){
    	int maxValue = Integer.MIN_VALUE;
    	for(int i = 0;i<input.length;i++){
    		if(input[i]>maxValue){
    			maxValue = input[i];
    		}
    	}
    	return maxValue;
    }
    
    //找到数组中最小的数
    public static int findMin(int[] input){
    	int minValue = Integer.MAX_VALUE;
    	for(int i = 0;i<input.length;i++){
    		if(input[i]<minValue){
    			minValue = input[i];
    		}
    	}
    	return minValue;
    }
    
    //找到排位第k大个数值
    public static int findKValue(int[] input, int k, int minValue, int maxValue){
    	int midValue = (maxValue+minValue)/2;
    	int count = getCount(input, midValue);
    	while(count!=k){					//当比midValue大的数的个数正好等于k时就可以跳出循环,并返回midValue,即第k大的数值
    		if(count>k){
    			minValue = midValue;
    		}else{
    			maxValue = midValue;
    		}
    		midValue = (maxValue+minValue)/2;
        	count = getCount(input, midValue);
    	}
    	return midValue;
    }
    
    //找出数组中比num大的数的个数
    public static int getCount(int[] input, int num){
    	int result = 0;
    	for(int i = 0;i<input.length;i++){
    		if(input[i]>num){
    			result++;
    		}
    	}
    	return result;
    }
  
}

//解法5:类似于桶排序的方式,以空间换时间O(N)
public class Main {  
	  
    public static void main(String[] args) throws Exception {  
    	int[] result1 = findMaxKNum1(new int[]{3,4,5,3,2,1,6,8},3);
    	for(int i = 0;i<result1.length;i++){
    		System.out.print(result1[i]+" ");
    	}
    	System.out.println();
    }  
  
    public static int[] findMaxKNum1(int[] input, int k) throws Exception {  
    	int maxValue = 10;
    	int[] count = new int[maxValue];
    	for(int i = 0;i<input.length;i++){
    		count[input[i]]++;
    	}
    	int[] result = new int[k];
    	int temp = 0;
    	for(int i = maxValue-1;i>=0;i--){
    		while(count[i]>0){
    			count[i]--;
    			result[temp] = i;
    			temp++;
    			if(temp == k){			//如果数量够了就可以跳出循环
    				break;
    			}
    		}
    		if(temp == k){				//如果数量够了就可以跳出循环
				break;
			}
    	}
    	return result;
    }
  
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值