寻找最大的k个数

来源:互联网 发布:ae软件下载官方中文版 编辑:程序博客网 时间:2024/06/05 14:12

题目描述:输入n个整数,输出其中最大的k个。

举例:输入序列1、2、3、4、5、6、7、8,输出最大的4个数字为5、6、7、8。

可能存在的条件限制:

要求 时间 和 空间消耗最小、海量数据、待排序的数据可能是浮点数等

方法一:对所有元素进行排序,之后取出前K个元素,不提倡使用

思路:使用最快排序算法,选择快排 或 堆排

时间复杂度:O(n*logn) + O(K) = O(n*logn)

特点:需要对全部元素进行排序,K = 1 时,时间复杂度也为O(n*logn)

注意:题中只需得到最大的K个数,而不需要对后面N-K个数排序

方法二:只需要对前K个元素排序,不需要对N-K个元素进行排序,不提倡使用

思路:使用 选择排序 或 起泡排序,进行K次选择,可得到第k大的数

时间复杂度:O(n*k)

方法三:不对前K个数进行排序 + 不对N-k个数排序,可以使用

思路:寻找第K个大元素。

具体方法:使用类似快速排序,执行一次快速排序后,每次只选择一部分继续执行快速排序,直到找到第K个大元素为止,此时这个元素在数组位置后面的元素即所求。

在数组S中找出一个元素X,把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素小于X。
这时有两种情况:
1. Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数;
2. Sa中元素的个数大于等于k,则返回Sa中的第k大数。

时间复杂度:因为每次只选择一部分递归,所以时间复杂度为N(1+1/2+1/4+....+1/x)<2N,所以复杂度为O(N).

       若随机选取枢纽,线性期望时间O(N)。

       若选取数组的“中位数的中位数”作为枢纽,最坏情况下的时间复杂度O(N)

以下代码用的是中位数法,得到最大的K个数。

下面的方法是找到第K个最大元素,后K个数即为前K个最大的数。

public static void main(String[] args) { searchKMax s = new searchKMax(); int a[]={20,100,4,2,87,8,9,5,46,260};   int Len=a.length; int K=5; s.FindKMax(a , 0 , Len- 1 , K); for(int i = Len-K ; i < Len; i++){      System.out.print(a[i]+" "); }}/*查找数组第K个最大的元素,index:返回数组中最大元素中第K个元素的下标(从0开始编号),high为数组最大下标*/int FindKMax(int a[],int low,int high,int k){   int mid;   int index=-1;   if(low < high){     mid = partition(a , low , high);        int rightlen = high - mid + 1; //右半边的长度        if(rightlen == k){        index=mid; //返回第k个位置        }else if(rightlen < k){        index=FindKMax(a , low , mid-1, k-rightlen);        }else{                index=FindKMax(a , mid + 1 , high , k);        }   }   return index;}/* * 将其他数与枢纽元比较,比枢纽元小的放在枢纽元左边,比它大的放在右边,划分为两个部分 */public int partition(int[] array,int left,int right){//选取枢纽元,不要选择第一个元素,一般用三数中值法求枢纽元,把枢纽元放到最左边int pivot = median3(array,left,right);int low = left+1;//从第二个数开始找int high = right;//找到第一个比枢纽元小的数,两者交换while(true){//找到第一个比枢纽元大的数while(array[low] <= pivot && low < high)low++;//找到第一个第枢纽元小的数while(array[high] > pivot)high--;//如果左指针<右指针,则将两者交换if(low < high){swap(array,low,high);}else{break;}}/* * 将放在最左边的枢纽元与high指针上的数交换, * 至此枢纽元左边的数都是小于它的数,右边的数都是大于它的数 */swap(array,left,high);return high;}/* * 三数中值分割法确定枢纽元,取left,right,center三个数的中值 */public int median3(int[] array ,int left,int right){int center = (left+right)/2;if(array[left] > array[center]){swap(array,left,center);}if(array[left] > array[right]){swap(array,left,right);}if(array[right] < array[center]){swap(array,right,center);}//经过以上三个判断,中值在center位上swap(array,center,left);//把枢纽元放在最左边return array[left];//枢纽元的值}/* * 将i和j上的数字交换 */public void swap(int[] array,int i,int j){int temp = array[i];array[i] = array[j];array[j] = temp;}

0 0
原创粉丝点击