1. 题目
在未排序的数组中找到第 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
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
Related Topics 堆 分治算法
👍 1112 👎 0
2. 题解
2.1 解法1: 排序
class Solution {
public int findKthLargest(int[] nums, int k) {
Arrays.sort(nums);
return nums[nums.length - k];
}
}
2.2 解法2: 优先队列(堆)
建立一个大小为 k 的最小堆, 保存数组中最大的 k 个元素
- 当堆不满时, 将元素入堆
- 当堆满时, 比较堆顶元素 a与当前元素b
当堆顶元素 < 当前元素时, 堆顶出堆, 将当前元素入堆
class Solution {
public int findKthLargest(int[] nums, int k) {
if (nums.length==0){
return 0;
}
PriorityQueue<Integer> minHeap=new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
});
for (int i = 0; i < k; i++) {
minHeap.offer(nums[i]);
}
for (int i = k; i < nums.length; i++) {
int temp= minHeap.peek();
if (temp<nums[i]){
minHeap.poll();
minHeap.offer(nums[i]);
}
}
return minHeap.peek();
}
}
2.3 解法2: 基于快速排序的分治算法
使用一次快排的算法代码, 返回值改为 排序后的支点位置, 因为一趟快排的结果是将支点元素放到其应该在的位置, 即第 index 个 小的元素
注意点: 分区的终止条件, 应该返回 left的下标, 而不是 0;
class Solution {
public int findKthLargest(int[] nums, int k) {
if (nums.length == 0) return 0;
int target = nums.length - k;
int left = 0, right = nums.length - 1;
while (true) {
int index = partition(nums, left, right);
if (index == target) {
return nums[index];
} else if (index < target) {
left = index + 1;
} else {
right = index - 1;
}
}
}
public int partition(int[] nums, int left, int right) {
if (left >= right) return left;// 终止条件, 注意返回 左下标元素
int i = left, j = right;
int pivot = nums[left];// 找支点
while (i < j) {
while (i < j && nums[j] >= pivot) j--;
nums[i] = nums[j];
while (i < j && nums[i] <= pivot) i++;
nums[j] = nums[i];
}
nums[i] = pivot;// 放入支点
return i;
}
}