1.题目描述
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度 O(nlogn)O(nlogn),空间复杂度 O(1)O(1)
数据范围:0≤n≤10000≤n≤1000, 1≤K≤n1≤K≤n,数组中每个元素满足 0≤val≤100000000≤val≤10000000
示例1
输入:
[1,3,5,2,2],5,3返回值:
2示例2
输入:
[10,10,9,9,8,7,5,6,4,3,4,2],12,3返回值:
9说明:
去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9
2.解题思路
1.大根堆
使用Java中的优先队列,用a中的元素构建一个大根堆,然后依次弹出堆顶的前k-1个元素,此时的堆顶元素即为第k大的元素。
2.快速排序+二分查找
使用partition函数对数组进行快速排序得到一个逆序排列,选择第一个元素作为基准元素,然后从后向前找比基准元素大的元素,找到后放在基准元素的位置,此时后面的那个位置就空出来了,就需要从前向后找比基准元素小的元素,放在后面的位置;退出循环后,基准元素就放在左指针指向的位置,此时基准元素所在位置就是最终有序后应该位于的位置。我们只需要判断它是不是在下标为k-1的位置上,如果是就说明它就是第k大元素,如果它>k-1,说明应该对它的左子区间中寻找目标元素;如果它< k-1,说明应该到它的右子区间寻找目标元素。
3.代码实现
思路一-大根堆
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
public Comparator<Integer> comparator = new Comparator<Integer>(){
@Override
public int compare(Integer i, Integer j) {
if (i < j) {
return 1;
} else if (i > j) {
return -1;
} else {
return 0;
}
}
};
public int findKth (int[] a, int n, int K) {
// write code here
PriorityQueue<Integer> pq = new PriorityQueue<>(comparator);
for (int i = 0; i < a.length; i++) {
pq.offer(a[i]);
}
for (int i = 1; i < K; i++) {
pq.poll();
}
return pq.peek();
}
}
思路二-快速排序+二分查找
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param a int整型一维数组
* @param n int整型
* @param K int整型
* @return int整型
*/
public int partition(int[] a, int l, int r, int k) {
int temp = a[l];
int i = l, j = r;
//逆序划分
while (i < j) {
//比基准元素大的放前面
while (i < j && a[j] <= temp) {
j -= 1;
}
a[i] = a[j];
//比基准元素小的放后面
while (i < j && a[i] >= temp) {
i += 1;
}
a[j] = a[i];
}
//找到了基准元素所在位置
a[i] = temp;
if (i + 1 == k) {
return a[i];
} else if (i + 1 < k) {
return partition(a,i+1,r,k);
} else {
return partition(a,l,i-1,k);
}
}
public int findKth (int[] a, int n, int K) {
// write code here
return partition(a,0,n-1,K);
}
}