给定一个整数数组arr,同时给定它的大小n和要找的K(K在1到n之间),返回第K大的数。
解法一: 结合快排思想,将数组从大到小排序的过程中返回确定好的元素的下标,与k比较,将范围逐渐缩小。
public class Test {
public static void main(String[] args) {
int[] arr = new int[]{6,4,5,7,8};
int n = findKth(arr, 5, 2);
System.out.println(n);
}
public static int findKth(int[] a, int n, int K) {
// write code here
int left = 0;
int right = n - 1;
int k = K-1; // 若数组“有序”,第k大为K-1下标的数
while (true) {
int index = partition (a, left, right); // 将返回下标数与k值比较
if (k == index) { // 相等说明找到了
return a[index]; // 返回index数值
} else if (index < k) { // index < k说明要找的数字还在右边
left = index + 1; // 则将left置位index + 1,直接找右半部分
} else {
right = index - 1; // 反之找左半边
}
}
}
public static int partition (int[] arr, int left, int right) {
// 取第一个(left下标)数为key
// 将剩余数与key比较
int key = arr[left];
int l = left; // l代表下标比较小的位置
for (int i = left; i <= right; i++) { // 用i遍历数组
if (arr[i] > key) { // 找出比key大的数
l++; // l及l之前的数都比key大,所以l++
swap(arr, l, i); // 把arr[l]与arr[i]交换位置
}
}
// 循环结束后l前边的数字比key大,l后边的数字比key小
swap(arr, left, l); // 最终将key的值放到l位置上
return l; // 返回key的下标l
// 结束之后key值左边比key大,key值右边比key小
}
private static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
以上也可以将partition 函数换成快速排序的partition函数
public static int partition (int[] arr, int left, int right) {
int l = left;
int r = right;
int key = arr[left];
while(l < r) {
while(l < r && arr[r] <= key) {
r--;
}
if (l < r) {
arr[l] = arr[r];
l++;
}
while(l < r && arr[l] >= key) {
l++;
}
if (l < r) {
arr[r] = arr[l];
r--;
}
}
return l;
}