描述
以尽量高效率求出乱序中的k小数
输入
第一行 数组长度
第二行 数组元素 空格隔开
第三性 第几小的数
输出
第k小的数
样例输入
5
6 1 2 9 3 8
2
样例输出
2
解题思路
利用快速排序找到主元的位置,判断主元是第几小的
主元位置大了剪掉右边的
主元位置小了剪掉左边的
假设要找第三小的数
主元的位置比最要找数大时剪掉右边的
主元的位置比要找的数小时剪掉左边的
代码示例
/*
* @Description:
* 寻找k小数
* @param arr
* 整型数组
* @param begin
* 下标开始
* @param end
* 下标结尾
* @param k
* 第几小的数
* @return
* 返回整数
*/
static int selectK(int[] arr,int begin,int end,int k) {
int q = partition(arr,begin,end);//先找到中间值,看中间值是第几小的
int qk = q+1;//第qk小
if(qk>k) {//中间值大于要找的往左找
return selectK(arr, begin, q-1, k);
}else if(qk<k) {//中间值小于要找的往右找
return selectK(arr, q+1, end, k);
}
return arr[q];
}
/*
* @Description:
* 找到较为中间值
* @param arr
* 数组
* @param begin
* 下标开头
* @param end
* 下标结尾
* @return
* 返回中间值位置
*/
static int partition(int[] arr,int begin ,int end) {
//三点确定法
int indexMid = (begin+end)>>1;
if(arr[begin]>=arr[indexMid] && arr[begin]<=arr[end]) {
indexMid = begin;
}else if(arr[end]>=arr[begin] && arr[end]<=arr[indexMid]) {
indexMid = end;
}
util.swap(arr, begin, indexMid);
//把三点确定法确定的值和第一个值交换,这样不影响
int poivt = arr[begin];
int left = begin+1;
int right = end;
while(left<=right) {
while(left<=right && arr[left]<=poivt)left++;
while(left<=right && arr[right]>poivt)right--;
if(left<right)
util.swap(arr, left, right);
}
util.swap(arr, begin, right);
return right;
}
我这里调试是直接调用一个随机的数组
public static void main(String[] args) {
int[] arr = util.getRandomArr(1000*1000, 1, 100000000);
int k = 5;
long now = System.currentTimeMillis();
System.out.println(selectK(arr, 0, arr.length-1, k));
System.out.println(System.currentTimeMillis()-now+"ms");
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
结果