题目描述
设计一个找到数据流中第K大元素的类(class)。注意是排序后的第K大元素,不是第K个不同的元素。
你的 KthLargest 类需要一个同时接收整数 k 和整数数组nums 的构造器,它包含数据流中的初始元素。每次调用 KthLargest.add,返回当前数据流中第K大的元素。
解法1:优先队列
利用priority_queue这种数据结构。本题中为升序的优先队列,且初始化为有k个INT_MIN的队列。add函数的实现为:如果加入的数字小于优先队列的队首,则函数不做处理,返回队首的元素;否则,将队首的元素出队,将该数字加入队列(在push操作中完成对队列重新升序排序)。题目的意图就是每次add函数的返回值就是此时该数据流的第k个最大的元素。
priority_queue补充知识:
1.普通队列具有先进先出的特点。而在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 的特征。
2.使用时需包括头文件#include
3.基本操作:
- top 访问队头元素
- empty 队列是否为空
- size 返回队列内元素个数
- push 插入元素到队尾 (并排序)
- pop 弹出队头元素
4.定义:priority_queue<Type, Container, Functional>
Type 就是数据类型,Container 就是容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector),Functional 就是比较的方式。
例:
//升序队列 priority_queue <int,vector,greater > q;
//降序队列 priority_queue <int,vector,less > q;
代码如下:
KthLargest.h
#pragma once
#include<iostream>
#include<queue>
using namespace std;
class KthLargest
{
public:
KthLargest(int k, vector<int>& nums);
int add(int val);
private:
priority_queue<int, vector<int>, greater<int>>* q;
int size;
};
KthLargest.cpp
#include "KthLargest.h"
KthLargest::KthLargest(int k, vector<int>& nums)
{
size = k;
q = new priority_queue<int, vector<int>, greater<int>>(size, INT_MIN);
int i;
for (int i = 0; i < nums.size(); i++)
{
add(nums[i]);
}
}
int KthLargest::add(int val)
{
if (val < (*q).top())
return (*q).top();
else
{
(*q).pop();
(*q).push(val);
}
return (*q).top();
}
main.cpp
#include"KthLargest.h"
int main()
{
int k = 3;
vector<int> v;
v.push_back(4);
v.push_back(5);
v.push_back(8);
v.push_back(2);
KthLargest* kthLargest = new KthLargest(3, v);
cout<<(*kthLargest).add(3);
cout<<(*kthLargest).add(5);
cout<<(*kthLargest).add(10);
cout<<(*kthLargest).add(9);
cout<<(*kthLargest).add(4);
return 0;
}
解法2:top-k算法
可以构建一个大小为k的小顶堆,且初始化为有k个INT_MIN的数组。小顶堆的堆调整函数也比较常用。add函数的实现:每当加入一个数时,都与堆顶元素作比较。如果小于堆顶元素,则函数不做处理,返回堆顶元素。否则,将这个加入值替换堆顶元素,并进行小顶堆的调整,返回堆顶元素。题目的意图就是每次add函数的返回值就是此时该数据流的第k个最大的元素。
代码如下:
KthLargest.h
#pragma once
#include<iostream>
#include<vector>
using namespace std;
class KthLargest
{
public:
KthLargest(int k, vector<int>& nums);
int add(int val);
void MinHeapify(vector<int>& nums, int length, int i);
private:
vector<int> v;
int size;
};
KthLargest.cpp
#include "KthLargest.h"
KthLargest::KthLargest(int k, vector<int>& nums)
{
size = k;
for (int j = 0; j < size; j++)
v.push_back(INT_MIN);
for (int i = 0; i < nums.size(); i++)
add(nums[i]);
}
int KthLargest::add(int val)
{
if (val > v[0])
{
v[0] = val;
MinHeapify(v, size, 0);
}
return v[0];
}
void KthLargest::MinHeapify(vector<int>& nums, int length, int i)
{
int n_left = i * 2 + 1; //节点i的左孩子
int n_right = i * 2 + 2; //节点i的右孩子节点
int min = i; //父节点
if (n_left < length && nums[n_left]<nums[min])
min = n_left;
if (n_right < length && nums[n_right]<nums[min])
min = n_right;
if (i != min) //最小值不是父节点
{
int temp = nums[i];
nums[i] = nums[min];
nums[min] = temp;
MinHeapify(nums, length, min);
}
}
main.cpp
#include"KthLargest.h"
int main()
{
int k=3;
vector<int> nums;
nums.push_back(4);
nums.push_back(5);
nums.push_back(8);
nums.push_back(2);
KthLargest m(k,nums);
cout << m.add(3)<<endl;
cout << m.add(5)<<endl;
cout << m.add(10)<<endl;
cout << m.add(9)<<endl;
cout << m.add(4)<<endl;
return 0;
}