题目链接:239. 滑动窗口最大值
题目:
1.暴力做法和为什么用双端队列
我们可以 双指针,一个指向第一个遍历,一个指向第三个向后遍历,每次遍历都for循环取出最大值,直到第二个快指针指向了最后一个就停止,这个时间复杂度为O(n*K),但是一般超过了10的9次方就会超时
由题意可得,超时了,所以我们可以用另一种方法,优先级队列(priority_queue)来写,虽然每次加了一个元素都会进行排序,但是队列只能删除第一个元素,用优先级队列顺序就会改变从而让不该先出去的元素出去了,所以不行,
有没有一种可以维护单调递减(单调递增)还能让删除顺序保持不变呢和删除的头就是最大值呢,我们,可以自己实现它,用双端队列成的单调队列。
2.单调队列解析
图像:
2.c++代码
class Solution {
public:
class MyQueue { //单调队列(从大到小)
public:
deque<int>que;
void pop (int value) {
if (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();
}
};
vector<int> maxSlidingWindow(vector<int>& nums, int k) {//单调队列
MyQueue que;
vector<int>result;
int size = nums.size();
for (int i = 0; i < k; i++) {
que.push(nums[i]);
}
result.push_back(que.front());
for (int i = k; i < size; i++) {
que.pop(nums[i - k]);
que.push(nums[i]);
result.push_back(que.front());
}
return result;
}
};
4.思路
每次滑动窗口,取出最大值到结果集中,删除头元素,加入新元素到末尾,维护单调队列是因为每次我们加数据都会和前一个比较,如果比他打就删掉前面的,总让最大的再第一个
5.问题和代码解析:
1.push
void push(int value) {
while (!que.empty() && value > que.back()) {
que.pop_back();
}
que.push_back(value);
}
};
while中第一个条件是如果队列为空,说明才遍历到第一个元素,不需要删除,直接加入队列中,
while中第二个条件是如果前面有元素还有比前面的大(说明前面的元素必然不是最大值),就可以把前面的元素删掉,让自己当老大,push自己
2.pop
void pop (int value) {
if (value == que.front()) {
que.pop_front();
}
}
这个条件是什么意思呢,就是如果 for (int i = k; i < size; i++) 遍历到的这个元素是最大值的话,就删掉他,
真正解释:因为push元素的时候把比最大值小的那些元素全部都删除了,所以顺序遍历时,会出现已经删掉的元素(匹配不到的数),所以我们不必要再次删除了, 直到匹配到的时候就说明这个数没删除,我们就可以删除了,因为是最大值,我们又需要把它加进结果集。
3.主函数
for (int i = 0; i < k; i++) {
que.push(nums[i]);
}
result.push_back(que.front());
for (int i = k; i < size; i++) {
que.pop(nums[i - k]);
que.push(nums[i]);
result.push_back(que.front());
}
把前三个数先加入,不然没元素删,再删除第一个(如果没匹配就已经删除了不必要删),加入下一个,放进第一个(第一个是最大的)到结果集
这题的关键是他的元素减少了,我们可以用下标匹配的方法,防止误删,顺序不变
题目链接:347. 前 K 个高频元素
1.暴力做法和思考
我们可以把nums进行map存储,map[nums[i]]++,再对map进行排序取出前面n个元素
但我们不许要这样,我们只需要维持前面的k个元素最大就行了,到第k+1个元素删掉最小的
所以我们要排序,用到优先级队列。
2.c++代码
class Solution {
public:
class compare{
public:
bool operator()(const pair<int, int>& b, const pair<int, int>& a) {
return b.second > a.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>>, compare>pri_que;
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
pri_que.push(*it);
if (pri_que.size() > k) {
pri_que.pop();
}
}
vector<int>result(k, 0);
for (int i = k - 1; i >= 0; i--) {
result[i] = pri_que.top().first;
pri_que.pop();
}
return result;
}
};
3.思路
先把数据存到map中,再定义一个优先级队列,遍历map,如果队列的元素个数大于k,就删掉一个,最后把优先级队列中的元素个数维持在k个元素,最后倒序输出就行了。
问题
用优先级队列先要定义一个比较函数
具体请看第一个栈与队列: