239 滑动窗口最大值
题目理解
给定整数数组nums,以k个数字为单位,寻找k个数字中的最大值。
思路
①超时的暴力解法:一开始想到的就是两层循环,一层遍历数组元素,直到第size()-k位,另一层寻找k个数字中的最大值。时间复杂度为O(kn)。
②题解中的方法,利用单调队列来处理数组。
首先,题目是寻找滑动窗口中的最大值,每次移动,相应的窗口会少一个元素再加一个元素,和出队、入队的操作很相似。我们需要的队列操作应该是每次pop一个元素,push一个元素,然后队首元素为队列中的最大值,也就是我们需要的结果,这样的话只有队列是严格单调递减的时候才能保证队首元素是最大值。
队列是一种容器适配器,需要底层容器来实现,缺省情况下用deque来实现。deque是一种双端队列,可在队首队尾进行push和pop操作。
对于push操作,想要将要push的元素和当前队列的队尾元素进行比较,因为我们要保证队列严格单调递减,所以如果当前元素值大于队尾元素,则队尾元素必定对滑动窗口最大值没有影响,舍去,这样直到当前元素小于队首元素,再加入队列。
对于pop操作,因为上一步的push操作会可能会舍去一部分元素,所以数组当前值可能已经不在队列中,因此需要判断队首元素是否是数组当前值,是的话pop,不是的话则不进行操作。
代码
class Solution {
private:
class Queue {
public:
deque<int> que;
void pop(int val) {
if(!que.empty() && que.front() == val) {
que.pop_front();
}
}
void push(int val) {
while(!que.empty() && val > que.back()) {
que.pop_back();
}
que.push_back(val);
}
int front() {
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
Queue que;
vector<int> res;
for(int i = 0;i < k;i++) {
que.push(nums[i]);
}
res.push_back(que.front());
for(int i = k;i < nums.size();i++) {
que.pop(nums[i - k]);
que.push(nums[i]);
res.push_back(que.front());
}
return res;
}
};
347 前K个高频元素
题目理解
给定数组,返回数组中出现频率最高的前K个元素。
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
思路
可以用哈希表把数组中不同元素出现的次数记录下来,接下来需要做的是怎样找到出现次数为前K大的元素呢。
考虑用优先级队列,也就是最小堆,队列长度为K,因为最小堆中每次弹出最小的元素,这样最后处理完哈希表后,剩下的K个元素即为最大的K个元素。
代码
class Solution {
public:
class com {
public:
bool operator()(pair<int,int>& p1,pair<int,int>& p2) {
return p1.second > p2.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> ma;
vector<int> res;
for(auto c : nums)
ma[c]++;
priority_queue<pair<int,int>,vector<pair<int,int>>,com> pri;
for(unordered_map<int,int>::iterator it = ma.begin();it != ma.end();it++) {
pri.push(*it);
if(pri.size()>k)
pri.pop();
}
}
while(!pri.empty()) {
res.push_back(pri.top().first);
pri.pop();
}
reverse(res.begin(),res.end());
return res;
}
};