Toasobi
数组中第K个最大元素(快速选择/优先队列、堆)
本文最后更新于2023年09月25日,已超过465天没有更新。如果文章内容或图片资源失效,请留言反馈,我会及时处理,谢谢!
- 题目:
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
方法一:优先队列、堆
PriorityQueue(优先队列)使用(需要定义比较器)
底层数据结构是完全二叉树(最小堆),队列顶元素永远是最小元素,同时每次poll是移除并返回队顶元素。优先队列每次删除和添加都会调整堆,使得堆的所有节点的值小于等于子节点的值
import java.util.Comparator;
import java.util.PriorityQueue;
public class Solution {
public int findKthLargest(int[] nums, int k) {
int len = nums.length;
// 使用一个含有 k 个元素的最小堆,PriorityQueue 底层是动态数组,为了防止数组扩容产生消耗,可以先指定数组的长度
PriorityQueue<Integer> minHeap = new PriorityQueue<>(k, Comparator.comparingInt(a -> a));
// Java 里没有 heapify ,因此我们逐个将前 k 个元素添加到 minHeap 里
for (int i = 0; i < k; i++) {
minHeap.offer(nums[i]);
}
for (int i = k; i < len; i++) {
// 看一眼,不拿出,因为有可能没有必要替换
Integer topElement = minHeap.peek();
// 只要当前遍历的元素比堆顶元素大,堆顶弹出,遍历的元素进去
if (nums[i] > topElement) {
// Java 没有 replace(),所以得先 poll() 出来,然后再放回去
minHeap.poll();
minHeap.offer(nums[i]);
}
}
return minHeap.peek();
}
}
优先队列的优化写法:(不懂可以动手画画过程)
class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue<Integer> heap = new PriorityQueue<>();
for (int num : nums) {
heap.add(num);
if (heap.size() > k) {
heap.poll();
}
}
return heap.peek();
}
}
- 方法二:快速选择(三路划分)
详细解答看:https://leetcode.cn/problems/kth-largest-element-in-an-array/solutions/2361969/215-shu-zu-zhong-de-di-k-ge-zui-da-yuan-d786p/?envType=study-plan-v2&envId=leetcode-75
对于nums.size() - small.size() < k等地方写的比较难看懂,但是动手画一下便知道为什么这样写了
public class Solution {
private int quickSelect(List<Integer> nums, int k) {
// 随机选择基准数
Random rand = new Random();
int pivot = nums.get(rand.nextInt(nums.size()));
// 将大于、小于、等于 pivot 的元素划分至 big, small, equal 中
List<Integer> big = new ArrayList<>();
List<Integer> equal = new ArrayList<>();
List<Integer> small = new ArrayList<>();
for (int num : nums) {
if (num > pivot)
big.add(num);
else if (num < pivot)
small.add(num);
else
equal.add(num);
}
// 第 k 大元素在 big 中,递归划分
if (k <= big.size())
return quickSelect(big, k);
// 第 k 大元素在 small 中,递归划分
if (nums.size() - small.size() < k)
return quickSelect(small, k - nums.size() + small.size());
// 第 k 大元素在 equal 中,直接返回 pivot
return pivot;
}
public int findKthLargest(int[] nums, int k) {
List<Integer> numList = new ArrayList<>();
for (int num : nums) {
numList.add(num);
}
return quickSelect(numList, k);
}
}
你的文章内容非常卖力,让人点赞。 http://www.55baobei.com/km4bHkoOQ6.html
你的文章充满了智慧,让人敬佩。 http://www.55baobei.com/yNQX7GTiZ5.html
你的文章内容非常精彩,让人回味无穷。 https://www.4006400989.com/qyvideo/73424.html
《在这个家庭里》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/113548.html