1 滑动窗口最大值
class Solution {
class MyQueue{ //单调队列
public:
deque<int> que;
void pop(int value){ //因为可能第一个已经被pop,所以要确认是否已经被pop,没被pop就pop
if(!que.empty() && value == que.front()){
que.pop_front();
}
}
void push(int value){
while(!que.empty() && value > que.back()){
que.pop_back();
}
que.push_back(value);
}
int getMax(){//单调队列的队首就是最大值
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueue que;
vector<int> result;
//首先把前三个加入队列
for(int i = 0; i < k; i++){
que.push(nums[i]);
}
//获取前三个中的最大值
result.push_back(que.getMax());
for(int i = k; i < nums.size(); i++){
que.pop(nums[i-k]);//首先pop出前三个的第一个
que.push(nums[i]);//滑动窗口前加入最后面的元素
result.push_back(que.getMax());
}
return result;
}
};
暴力解法也可以找到最大值:时间复杂度O(n × k);
通过自己构造单调队列,实现只维护最大值,同时保证队里的元素数值是由大到小的。
2 前k个高频元素
利用map统计每个数出现的频率,然后用sort排序(时间复杂度为O(nlogn));
我本来还想用map内部自动排序,后来想想才发现他是利用key排序的,而这里的key是nums数值。
使用优先级队列进行排序,只需要维护,前k个高频元素(时间复杂度为O(nlogk))
本题利用小顶堆,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素。
因为是从小到大,所以最后要通过倒序对结果集进行赋值,出来才是从大到小
class Solution {
struct cmp{
public:
bool operator()(const pair<int,int> &l, const pair<int, int> &r){
return l.second > r.second;
}
};
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> map;
for(int i = 0; i < nums.size();i++){
map[nums[i]]++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,cmp> pq;
for(unordered_map<int,int>::iterator it = map.begin(); it != map.end();it++){
pq.push(*it);
if(pq.size() > k){
pq.pop();
}
}
vector<int> result(k);
for(int i = k-1; i >=0 ; i--){//小顶堆,从小到大,所以后序遍历进行赋值
result[i] = pq.top().first;
pq.pop();
}
return result;
}
};
优先级队列priority_queue:(默认情况下是大顶堆)
大顶堆:进入队列之后,从大到小
小顶堆:进入队列之后,从小到大
优先级队列(priority_queue),不满足先进先出的条件,更像是数据类型中的“堆”。优先级队列每次出队的元素是队列中优先级最高的那个元素,而不是队首的元素。这个优先级可以通过元素的大小等进行定义。
大顶堆优先级就是大值,小顶堆优先级就是小值
priority_queue<typename, container, functional>
typename是数据的类型;
container是容器类型,可以是vector,queue等用数组实现的容器,不能是list,默认可以用vector;
functional是比较的方式,默认是大顶堆;如果使用C++基本数据类型,可以直接使用自带的less和greater这两个仿函数(默认使用的是less,就是构造大顶堆,元素小于当前节点时下沉)。
使用基本数据类型时,只需要传入数据类型,默认大顶堆,即less<>
使用自定义的数据类型的时候,可以重写比较函数,也可以进行运算符重载(less重载小于“<”运算符,构造大顶堆;greater重载大于“>”运算符,构造小顶堆)。
其实自带有pair<>进行比较的比较函数,但是先比较第一个元素,第一个相等比较第二个,而本题要实现的是根据value进行排序,所以要重写比较函数。