LeetCode239. 滑动窗口最大值
题目链接
视频讲解
自己实现
数组实现单调队列
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> que(nums.size());
int hh = 0, tt = -1;
vector<int> res;
for(int i = 0; i < nums.size(); i++) {
if(hh <= tt && que[hh] < i - k + 1) hh++;
while(hh <= tt && nums[que[tt]] <= nums[i]) tt--;
que[++tt] = i;
if(i >= k - 1) res.push_back(nums[que[hh]]);
}
return res;
}
};
双端队列实现单调队列
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
deque<int> que;
vector<int> res;
for(int i = 0; i < k; i++) {
while(!que.empty() && nums[que.back()] <= nums[i]) {
que.pop_back();
}
que.push_back(i);
}
res.push_back(nums[que.front()]);
for(int i = k; i < nums.size(); i++) {
while(!que.empty() && nums[que.back()] < nums[i]) {
que.pop_back();
}
que.push_back(i);
if(que.front() <= i - k){
que.pop_front();
}
res.push_back(nums[que.front()]);
}
return res;
}
};
题解
class Solution {
private:
class MyQueue {
public:
deque<int> que;
void pop(int value) {
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 front() {
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.front());
for (int i = k; i < nums.size(); i++) {
que.pop(nums[i - k]);
que.push(nums[i]);
result.push_back(que.front());
}
return result;
}
};
总结
- 用双端队列实现更好理解,实现寻找最大值队列里就单调递减,找最小值则单调递增
LeetCode347. 前 K 个高频元素
题目链接
视频讲解
自己实现
class Solution {
public:
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int>hash;
vector<int> res;
for(int i = 0; i < nums.size(); i++) {
hash[nums[i]]++;
}
int n = nums.size();
vector<int> count(n + 1, 0);
for(auto h : hash) {
count[h.second]++;
}
int c = 0, i = n;
while(c < k) {
c += count[i--];
}
for(auto h : hash) {
if(h.second > i) res.push_back(h.first);
}
return res;
}
};
题解
class Solution {
public:
class less{
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>hash;
vector<int> res;
for(int i = 0; i < nums.size(); i++) {
hash[nums[i]]++;
}
priority_queue<pair<int, int>, vector<pair<int, int>>, less>que;
for(auto h : hash) {
que.push(h);
if(que.size() > k) que.pop();
}
while(!que.empty()) {
res.push_back(que.top().first);
que.pop();
}
return res;
}
};
总结
- 用优先队列会比计数排序的方法更容易理解
- 为什么用小根堆,不用大根堆,因为优先队列要维护一个大小为
k
的队列,每次多的话就 pop
出一个,如果用大根堆,那么只能推出最大的一个,就会有问题 - 这里实现小根堆的
compare
的判断是用的 a.second > b.second
,跟其他比较函数的实现是相反的