给定整数数组 nums
和整数 k
,请返回数组中第 k
个最大的元素。
请注意,你需要找的是数组排序后的第 k
个最大的元素,而不是第 k
个不同的元素。
1、暴力法
class Solution {
public int findKthLargest(int[] nums, int k) {
int i = nums.length;
Arrays.sort(nums);
return nums[i-k];//要求的第k大的数,在从小往大排的过程中,排第(i-k)位
}
}
2.优先队列
class Solution {
public int findKthLargest(int[] nums, int k) {
int len = nums.length;
//优先队列,PriorityQueue堆中从小到大排列,其中堆顶最小,因此只需维护k个数的堆,
//如果当前堆不满,直接添加;
//堆满的时候,如果新读到的数小于等于堆顶,肯定不是我们要找的元素,只有新遍历到的数大于堆顶的时候,才
//将堆顶拿出,然后放入新读到的数,进而让堆自己去调整内部结构。
PriorityQueue<Integer> minQue = new PriorityQueue<>(k, Comparator.comparingInt(a -> a));
for(int i = 0;i < k;i++){
minQue.offer(nums[i]);//首先将前k个加入堆
}
for(int j = k ;j < len;j++){
int topQue=minQue.peek();
if(nums[j] > topQue){
minQue.poll();//删除堆顶
minQue.offer(nums[j]);//添加比堆顶大的数
}
}
return minQue.peek();//最后得出堆顶
}
}
3.减而治之(逐渐缩小问题规模)
public class Solution {
private static Random random = new Random(System.currentTimeMillis());
public int findKthLargest(int[] nums, int k) {
int len = nums.length;
int target = len - k;//记录第k大所在从小到大排列的第(len-k)位中
int left = 0;
int right = len - 1;
while (true) {
int index = partition(nums, left, right);
if (index < target) {
left = index + 1;
} else if (index > target) {
right = index - 1;
} else {
return nums[index];
}
}
}
private int partition (int [] nums, int left, int right){
if(right > left){
int randomindex = left+1+random.nextInt(right-left);
swap(nums ,left, randomindex);
}
int pivot = nums[left];
int j = left;
for(int i = left + 1;i <= right; i++){
if(nums[i] < pivot){
j++;
swap(nums,j,i);
}
}
swap(nums,left,j);
return j;
}
private void swap(int[] nums, int index1, int index2) {
int temp = nums[index1];
nums[index1] = nums[index2];
nums[index2] = temp;
}
}