Leetcode 239. 滑动窗口最大值
思路:每次都要维护窗口中元素最大值,且窗口是一直在变化的,可以用队列来实现,因为队列可以实现数据的进出。每次窗口中移除的元素不一定是最大值,所以不能用优先队列解决,优先队列只能弹出队首元素也就是最大值。
构造一个单调队列,先将前k
个元素加入到队列中,然后开始维护队列的队首,也就是窗口中的最大值,每次窗口移动就添加元素到队列或者弹出队列中的元素。如果窗口中移除的元素等于队列的队首元素,则弹出队首元素,最大值改变,如果待加入的元素不等于队首元素,但是比队尾元素大,则一直弹出队尾元素,知道队尾元素大于待加入元素,再将待加入元素入队。每次窗口移动后,队首元素即为窗口中元素的最大值
class Solution {
private:
class MyQueue{
public:
deque<int> dq; //用deque模拟单调队列
void pop(int value){
if(!dq.empty() && value == dq.front()) //如果要弹出的元素等于队列的最大值 则把最大值弹出
dq.pop_front(); //弹出最大值
}
void push(int value){
while(!dq.empty() && dq.back() < value) //如果待加入的元素小于队尾的元素就一直弹出队尾元素 直到队尾元素大于等于待加入元素
dq.pop_back();
dq.push_back(value);
}
int front(){ //返回队列的最大值
return dq.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> res;
MyQueue dq;
for(int i=0;i<k;i++){
dq.push(nums[i]); //先将前k个元素放入队列
}
res.push_back(dq.front());
for(int i=k;i<nums.size();i++){
dq.pop(nums[i-k]); //弹出不在窗口中的元素
dq.push(nums[i]); //将新进入窗口的元素加入队列
res.push_back(dq.front()); //更新窗口的最大值
}
return res;
}
};
Leetcode 347. 前 K 个高频元素
思路:可以用map
存储每个元素出现的次数,然后对频率进行排序。因为只需要前k个大的元素,所以只维护长度为k的序列。使用优先队列进行排序,重点是使用小根堆还是大根堆排序,应该使用小根堆排序,因为每次更新弹出最小的元素,剩下的就是前k
大的元素
class Solution {
public:
class mycomparison{ //小根堆
public:
bool operator()(const pair<int,int> &a,const pair<int,int> &b){
return a.second > b.second;
}
};
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>>,mycomparison> pri_que;
for(auto it :map){
pri_que.push(it);
if(pri_que.size()>k) //如果队列个数多于k个 则把最小的元素弹出 剩下的即为前k个大的数
pri_que.pop();
}
vector<int> res;
for(int i=0;i<k;i++){
res.push_back(pri_que.top().first);
pri_que.pop();
}
return res;
}
};