获取数组中第k小的元素
获取数组中第k小的元素
这类问题有几种方法:
-
数组中元素取值范围有限的情况下,适合使用哈希表的方式,一个哈希表长度为取值范围,初始值为0,有一个值取到就加1,然后从最小段开始搜索,直到找到第k小的元素所在的位置。该方法为O(n)的,空间复杂度是O(m),m为取值范围
-
k小的时候,适合构造一个长度为k的最小值数组。遍历原数组,同时维护这个最小值数组。该方法是O(nk)的,空间复杂度为O(k)
-
比较通用的方法是基于快排的,就是和快排步骤基本类似,但是每次找到枢纽后看枢纽的下标和k之间的关系:如果下标+1等于k,说明枢纽位置就是第k小的元素;如果下标加1大于k,说明第k小的元素在枢纽的左侧区域,所以再对左侧区域求枢纽并根据枢纽排序;相应的如果下标加一小于k,就说明在枢纽的右侧区域,所以之后对右侧求枢纽。该方法的空间复杂度是O(1)的,最差时间复杂度是O(n^2)的,例如我们每次都抽到最大的,相当于每次都要对剩下的排序,要排n-k次。但是平均复杂度是O(n)的,因为和快排不一样,我们每次只需要对选定的一半接着排序即可,所以平均来看如果每次选取的都是中央的元素(理想情况),那要排序的个数就是
n+1/2*n+1/4*n+1/8*n+...+1,因为1/2*n+1/4*n+1/8*n+...+1<n,所以整体是小于2n的。代码如下:
package com.jiading.getK; public class BasedQuickSort { private static int partition(int[]numbers,int begin,int end) { //每次选begin位置的作为枢纽 int kNum=numbers[begin]; int left=begin,right=end; while(left<right) { while(left<right && numbers[right]>=kNum) { right--; } numbers[left]=numbers[right]; while(left<right && numbers[left]<=kNum) { left++; } numbers[right]=numbers[left]; } numbers[left]=kNum; return left; } private static int getK(int k,int[]numbers,int begin,int end) { int index=partition(numbers,begin,end); if(index+1==k) { return numbers[index]; } if(index+1>k) { return getK(k, numbers, begin, index-1); }else { return getK(k, numbers, index+1, end); } } public static void main(String[]args) { int[]numbers= {9,1,2,8,7,3,6,4,3,5,0,9,19,39,25,34,17,24,23,34,20}; int k=getK(1,numbers,0,numbers.length-1); System.out.println(numbers[k]); } }

浙公网安备 33010602011771号