给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
提示:
- 1 <= k <= nums.length <= 104
- -104 <= nums[i] <= 104
解题思路
第一种暴力破解
直接对数组排序,然后选择Length-K的位置的数据就可以了
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length -k];
}
}
第二种优先队列
使用PriorityQueue优先队列来实现,其中PriorityQueue在默认情况下是小顶堆,我们在实现小顶堆的时候维护小顶堆的大小为K,最后将小顶堆的根节点就是数组中倒数第K大的元素。
class Solution {
public int findKthLargest(int[] nums, int k) {
//这个是使用优先队列来做
PriorityQueue<Integer> pq = new PriorityQueue<>(); // 小顶堆
for (int val : nums) {
pq.add(val);
if (pq.size() > k) // 维护堆的大小为 K
pq.poll();
}
return pq.peek();
}
}
时间复杂度 O(NlogK),空间复杂度 O(K)。
第三种快速排序
class Solution {
public int findKthLargest(int[] nums, int k) {
int left = 0,right = nums.length-1;
//找到最后排序完的下标
int target = nums.length-k;
while(true){
//首先找到排序后的每一个下标
int index = partition(nums,left,right);
if(target == index){
return nums[index];
}else if(target > index){
left++;
}else{
right--;
}
}
}
public int partition(int[] nums,int left,int right){
int pivot = nums[left];
int j = left;
for(int i = left+1;i<=right;i++){
//判断nums[i]的值与pivot是否相等
if(nums[i]<pivot){
j++;
swap(nums,j,i);
}
}
swap(nums,j,left);
return j;
}
//定义一个交换数据的函数
public void swap(int[] a,int i,int j){
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
但是这种快速排序的时间很慢,因为是从数组的第一个元素开始划分。后面发现使用一个随机元素作为标定点,执行时间会快很多。
import java.util.Random;
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;
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];
}
}
}
// 在区间 nums[left..right] 区间执行 partition 操作
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;
}
}