Day11- 第五章 栈与队列part03
今日内容:
● 239. 滑动窗口最大值
● 347.前 K 个高频元素
今日知识点:
● 优先队列
239. 滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
1、解题思路
滑动窗口最大值,滑动窗口类似单向队列,构建一个单向递减的队列,这样就能保证每次取队列的队头即为窗口最大值;每遍历一个数字a,就要在队列不空的情况下,循环与队尾的数比较,(这里解释一下因为队列是严格递减的,所以只用和队尾元素比较,队尾之前的队列已经严格递减了,相当于把队列元素中比a小的所有数出队)如果a大于队尾元素,那么队尾元素就要出队,直到队列为空或者a小于某一个队尾元素,那么a入队;当新的数入队的时候还需要判断队内元素个数是否小于等于k,这里不能使用size()函数,可以使用数组下标记录其位置队列中下标应该从[i-k+1,i], while(res.front() <= i - k) res.pop_front();这里bug一直没通过。
2.代码
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ans;
deque<int> res;
for(int i = 0; i < k ; i++){
while(!res.empty() && nums[i] >= nums[res.back()]){
res.pop_back();
}
res.push_back(i);
}
ans.push_back(nums[res.front()]);
for(int i = k; i < nums.size(); i++){
while(!res.empty() && nums[i] >= nums[res.back()]){
res.pop_back();
}
res.push_back(i);
while(res.front() <= i - k)
res.pop_front();
ans.push_back(nums[res.front()]);
}
return ans;
}
};
347. 前 K 个高频元素
给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
示例 1:
输入: nums = [1,1,1,2,2,3], k = 2
输出: [1,2]
示例 2:
输入: nums = [1], k = 1
输出: [1]
1.解题思路
解题思路很简单,使用map记录下每个数出现的次数,然后对value进行排序,这里使用小顶堆,设置堆的元素k个,因为要统计最大前k个元素,只有小顶堆每次将最小的元素弹出,最后小顶堆里积累的才是前k个最大元素,这里对堆不太熟悉,代码陌生。
2.代码
class Solution {
public:
static bool cmp(pair<int, int>& m, pair<int, int>& n) {
return m.second > n.second;
}
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int,int> res;
for(int i = 0; i < nums.size(); i++)
res[nums[i]]++;
//建立一个小顶堆
priority_queue<pair<int,int>, vector<pair<int,int>>,decltype(&cmp)> prique(cmp);
//
for(auto& [num,count] : res){
if(prique.size() == k){
if(prique.top().second < count){
prique.pop();
prique.emplace(num,count);
}
}
else
prique.emplace(num,count);
}
vector<int> ans;
while(!prique.empty()){
ans.emplace_back(prique.top().first);
prique.pop();
}
return ans;
}
};
总结
- 优先队列
priority_queue:优先队列,本质是堆实现。与队列不同的是,priority_queue只能访问队列头部的信息(使用top),且插入元素后,会自动排序。
- 基本操作
top(): 访问队头元素
empty(): 队列是否为空
size():返回队列内元素个数
push():插入元素到队尾 (并排序)
emplace():原地构造一个元素并插入队列
pop():弹出队头元素
swap():交换内容
- 定义
priority_queue<Type, Container, Functional>
Type :优先队列中元素的数据类型
Container :容器类型(Container必须是用数组实现的容器,比如vector,deque等等,但不能用 list。STL里面默认用的是vector)【简单理解就是用什么容器实现这个优先级队列】
Functional :比较的方式,当需要用自定义的数据类型时才需要传入这三个参数,使用基本数据类型时,只需要传入数据类型,默认是大顶堆【有greater、less和自定义函数,其中greater使得优先队列中的元素升序排列,所以第一个元素(头部)就是最小的元素,也就是小顶堆;less使得元素降序排列,那么第一个元素就是最大的,也就是大顶堆。】