获取数组中第k小的元素

获取数组中第k小的元素

这类问题有几种方法:

  1. 数组中元素取值范围有限的情况下,适合使用哈希表的方式,一个哈希表长度为取值范围,初始值为0,有一个值取到就加1,然后从最小段开始搜索,直到找到第k小的元素所在的位置。该方法为O(n)的,空间复杂度是O(m),m为取值范围

  2. k小的时候,适合构造一个长度为k的最小值数组。遍历原数组,同时维护这个最小值数组。该方法是O(nk)的,空间复杂度为O(k)

  3. 比较通用的方法是基于快排的,就是和快排步骤基本类似,但是每次找到枢纽后看枢纽的下标和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]);
    	}
    }
    
posted @ 2020-04-07 18:42  别再闹了  阅读(591)  评论(0)    收藏  举报