Question 215: Kth Largest Element in an Array
Difficulty: Medium
题目描述
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例:
输入: [3,2,1,5,6,4] 和 k = 2输出: 5
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4输出: 4
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
题目分析
显然这道题可以先排序,再去找第K大的值,但这种暴力解法显然不是最优解。在这里我们可以维护一个大小为K的最小堆minheap来实现。
本题目的算法并不难,但我们需要了解一下堆的概念。
关于堆
堆就是用数组实现的二叉树,所有它没有使用父指针或者子指针。堆根据“堆属性”来排序,“堆属性”决定了树中节点的位置。
堆的常用方法:
•构建优先队列•支持堆排序•快速找出一个集合中的最小值(或者最大值)
堆分为两种:最大堆 和 最小堆,两者的差别在于节点的排序方式。
在最大堆中,父节点的值比每一个子节点的值都要大。在最小堆中,父节点的值比每一个子节点的值都要小。这就是所谓的“堆属性”,并且这个属性对堆中的每一个节点都成立。
这是一个最大堆,,因为每一个父节点的值都比其子节点要大。10
比 7
和 2
都大。7
比 5
和 1
都大。
根据这一属性,那么最大堆总是将其中的最大值存放在树的根节点。而对于最小堆,根节点中的元素总是树中的最小值。堆属性非常的有用,因为堆常常被当做优先队列使用,因为可以快速的访问到“最重要”的元素。
题解
显然,遍历数组中的元素,并维护一个大小为K的minHeap,最后堆顶元素即为所求。遍历每个元素,并每次都要进行一次heapify,则时间复杂度为O(N log K),由于维护了大小为K的minHeap则空间复杂度为O(log K)。
//Java 解法class Solution { public int findKthLargest(int[] nums, int k) { PriorityQueue<Integer> minHeap = new PriorityQueue<>(k, new Comparator<Integer>(){ @Override public int compare(Integer o1, Integer o2){ if(o1.equals(o2)) return 0; return o1 < o2 ? -1 : 1; } } ); for(int i = 0; i < nums.length; i++){ if(minHeap.size() < k){ minHeap.add(nums[i]); }else if(nums[i] > minHeap.peek()){ minHeap.poll(); minHeap.add(nums[i]); } } return minHeap.poll(); }}
#python 解法class Solution: def findKthLargest(self, nums, k): """ :type nums: List[int] :type k: int :rtype: int """ return heapq.nlargest(k, nums)[-1]