题目:
在未排序的数组中找到第 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 ≤ 数组的长度。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
1.暴力法起步:
直接给数组排序,时间复杂度O(n*logn),Arrays.sort是按照从小到大的顺序排序。
要求第K大的元素,那么就返回下标为 len - k 的元素就行了
比如 第4大的元素,数组一共6个元素
第4大就是从前往后的第2个 2 = 6 - 4
比如 第2大的元素,数组一共6个元素
第2大就是从前往后的第4个 2 = 6 - 4
So :
//sort 算是暴力办法
public static int findKthLargest(int[] nums, int k) {
if(nums == null || nums.length == 0)
return 0;
Arrays.sort(nums);
int len = nums.length;
return nums[len - k];
}
这是个中等的题,第一下用暴力法做出来的时候都惊呆了,就这么点?
事实证明,该暴力法还比较快,只用了2ms
2.堆
但是肯定没有这么简单,既然是中等题就该有中等题的样子
想了下别的算法,这个时候就涉及到了堆这个数据结构。
维基百科:链接.
给定堆中任意节点P和C,若P是C的母节点,那么P的值会小于等于(或大于等于)C的值”。
若母节点的值恒小于等于子节点的值,此堆称为最小堆(min heap);
反之,若母节点的值恒大于等于子节点的值,此堆称为最大堆(max heap)
那么我们是否可以维护一个最小堆 堆的堆顶节点是最小值,如果堆一直维持在k个元素,那么堆顶就是第K大的元素。
通过for循环,每次往最大堆中加入数组的元素,
- 当最大堆的size < k的时候,只管add
- 当size == k的时候,先add元素,堆会自动将最大的值放到堆顶(堆自动维护堆的性质),然后再移除该堆顶节点
最后的时候,返回堆顶节点即可。
代码1:
//最小堆
public static int findKthLargestDemo(int[] nums, int k) {
if(nums == null || nums.length == 0)
return 0;
PriorityQueue<Integer> heap = new PriorityQueue<>(nums.length, (n1,n2) -> n1 - n2);
for(int i : nums) {
heap.add(i);
if(heap.size() > k)
heap.poll();
}
return heap.peek();
}
当然,也可以把堆的数量直接限制在K个
代码2:
//k 个元素的最小堆
public int findKthLargestDemo2(int[] nums, int k) {
int len = nums.length;
// 使用一个含有 k 个元素的最小堆
PriorityQueue<Integer> minHeap = new PriorityQueue<>(k, (a, b) -> a - b);
for (int i = 0; i < k; i++) {
minHeap.add(nums[i]);
}
for (int i = k; i < len; i++) {
//获取堆顶节点的值
Integer top = minHeap.peek();
//如果当前遍历的数组元素大于堆顶节点,堆顶弹出,遍历的元素进去
if (nums[i] > top) {
minHeap.poll();
minHeap.add(nums[i]);
}
}
return minHeap.peek();
}
堆的知识还有一堆 ,比如堆排序,如何自己实现一个堆,堆的增删查的底层如何实现,
果然,中等题还是有中等题的原因,学起来