239. 滑动窗口最大值
hard
心得
- 想的暴力遍历,显然不是最优
题解
- 时间复杂度O(N),空间O(N),虽然push中有while,但是每个元素操作数最多2次
- 用单调队列解决,而不是优先队列,因为大顶堆每次只能弹出最大值,而窗口移动,无法保持动态更新
- 队列始终保持单调性(单减),结果即为队首元素
- 注意队列的非空判断,默认的duque结构支持首尾操作
- 切记单调队列不是对其中元素进行排序,这样的话跟优先队列没有区别
class MyQueQue {
public:
deque<int> que; // 默认队列使用deque结构,双端可操作
// 移除时,如果不是队首元素则保留,即队列保留的是单调队列,最值,可能不在原来的第一个位置
void pop(int value){
if (!que.empty() && que.front() == value) {
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();
}
};
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
MyQueQue 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;
}
};
347. 前 K 个高频元素
mid
心得
- 考虑map保存次数,然后value排序,但是感觉两步骤麻烦
- 题目给的暗示复杂度NLogN考虑,先遍历N,然后快排排序不超过NlogN,但是排序其实不需要所有元素都参与,主要k个即可,考虑此二叉树调整正好logK
- 多思考多尝试
题解
- 时空复杂度nlongk,n
- top k问题,大小堆,堆是一颗完全二叉树,树中每个结点的值都不大于或者小于其左右孩子的值,如果大顶堆,则父节点大于左右孩子,反之小顶堆
- C++中优先级队列(priority_queue)即为大小堆的实现,由于其对外接口只是从对头取元素,队尾添加元素,看起来很像一个队列,默认大顶堆,小顶堆需要自己写comparison
- 本题用的小顶堆,如果用大顶堆,每次堆顶是最大元素,无法前k个,所以用的小顶堆,维护size k,超过k每次移除最小即可
class Solution {
public:
// 小顶堆
class mycomparison {
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.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]]++;
}
// 频率排序,定义小顶堆,大小k,写法看不懂?
priority_queue<pair<int, int>, vector<pair<int, int>>, mycomparison> pri_que;
// 固定大小k的小顶堆,扫描所有频率的数值
for (unordered_map<int, int>::iterator it = map.begin(); it != map.end(); it++) {
pri_que.push(*it);
if (pri_que.size() > k) { // 始终保持大小k,移除最小的,这样剩下的就是最大的
pri_que.pop();
}
}
// 优先队列的值目前只能弹出最小,所以需要逆序
vector<int> result(k);
for (int i = k-1; i >= 0; i--) {
result[i] = pri_que.top().first;
pri_que.pop();
}
return result;
}
};