(一)预备知识:堆与堆排序
二叉堆是一种非线性的数据结构,是一种完全二叉树的结构,分为大顶堆和小顶堆两种,其中大顶堆是指树中各父节点的值总是大于等于任何一个子节点的值;而小顶堆则是定义为树中各父节点的值总是小于等于任何一子节点的值。
一般用二叉堆实现优先级队列,其内部调整的时间复杂度为O(logN),C++的标准STL库的优先级队列包括以下5种操作:
(1)取堆顶操作:H.top()
(2)判断堆空操作:H.empty()
(3)添加元素入堆:H.push(int x)
(4)元素弹出堆:H.pop()
(5)求堆中元素个数:H.size()
其中,取堆顶和弹出堆操作都需要调整堆的结构,时间复杂度都是O(logN),而其他三个操作的时间复杂度都是O(1)。
(二)求数组中第k大的元素
已知一个未排序的数组,求该数组中的第K大元素,例如数组如下:
[3,2,1,5,6,4],k=2,第2大数字为5
算法设计:可以维护一个size为k的小顶堆Q,Q的堆顶用于存放每次的第k大的元素。将数组中的元素依次入堆,当Q.size()小于k时(堆并未建完),元素直接入堆;否则,判断当前元素x与堆顶元素Q.top()的大小,若x>Q.top(),说明此时的堆顶元素并非第k大,故将堆顶元素弹出,并将x入堆。
代码设计如下:
int findKthLargest(std::vector<int> nums, int k) {
// 小顶堆
std::prior queue<int, std::vector<int>, std::greater<int>> Q;
for (int i=0; i<nums.size(); i++) {
if (Q.size() < k) {
Q.push(nums[i]);
} else if (nums[i] > Q.top()) {
Q.pop();
Q.push(nums[i]);
}
}
return Q.top();
}