题目
以较高的效率求一组无序数组中按从小到大排序后第K个数的值。
用上了我学会但不太熟的双指针快速排序。
代码如下:
public static int selectK(int[] arr, int l, int r, int k) {
int q = partition(arr, l, r);//
int qk = q - l + 1;//元素在数组中的位置
if (qk == k) return arr[q];
else if (qk > k) return selectK(arr, l, q - 1, k);//比目标位置大则在左边区间找
else return selectK(arr, q + 1, r, k - qk);//比目标位置小则在右边区间找
}
//快速排序
public static int partition(int[] arr, int l, int r) {
int mid=l+(r-l>>1);
mid=Utils.getMid(arr,l,mid,r);//我自己封装的获取三个数中为中位数的方法
if (mid!=l){
Utils.swap(arr,l,mid);//自己封装的方法
}
int p = arr[l];
int left = l + 1;
int right = r;
while (left <= right) {
while (left <= right && arr[left] <= p) {
left++;
}
while (left <= right && arr[right] > p) {
right--;
}
if (left < right) {
Utils.swap(arr, left, right);
}
}
Utils.swap(arr, l, right);
return right;
}
本题给我带来的收获是加深了我对双指针快速排序的应用。
首先先将初始数组第一次划分partition(arr, 0, arr.length-1)。将arr[l],arr[mid],arr[r]中为中位数的值放到应该在的位置然后返回right。
因为对右指针的限定条件为left<=right&&arr[right]>p 所以right最后会停在左侧数组中最后一个比p小的位置,此位置即为本次p应该所在的位置。然后用q-l+1可以得出p在排序好之后所处位置。
测试代码:
结果如下: