https://leetcode.cn/problems/sliding-window-maximum/description/
这题的难点在于如何快速获取每个窗口内的最大值
对于每一个窗口,需要执行以下步骤:
<aside> 💡
思路:我们需要创建一种队列,它拥有正常队列的push和pop功能,且能获取队列中的最大值
单调队列
主要思想:队列没有必要维护窗口里的所有元素,只需要维护有可能成为窗口里最大值的元素就可以了,同时保证队列里的元素数值是由大到小的
// 实现单调队列类,需要理清楚三个步骤:
// 1.如何push元素?
// 2.如何pop元素?
// 3.如何获取窗口内的最大值?
class MyQueue {
public:
void push(int val) {
// 弹出队列中所有比推入值小的元素
while (!que.empty() && val > que.back())
que.pop_back();
que.push_back(val);
}
void pop(int val) {
// 队头元素一定是当前最大值
// 小于该元素的在push时就已经被弹出
// 所以只有最大值刚好在队头时需要进行pop
if (val == que.front())
que.pop_front();
}
int getMax() {
return que.front();
}
deque<int> que;
};
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> ans;
MyQueue que;
for (int i = 0; i < k; ++i) {
que.push(nums[i]);
}
ans.push_back(que.getMax());
for (int left = 1; left + k - 1 < nums.size(); ++left) {
que.push(nums[left + k - 1]);
que.pop(nums[left-1]);
ans.push_back(que.getMax());
}
return ans;
}
<aside> 💡
这题用哈希表也能解,主要利用了map对元素进行排序的特性(不过性能很低)
</aside>
// 哈希表解法——利用了map自动排序的特性
vector<int> maxSlidingWindow0(vector<int>& nums, int k) {
// <值, 窗口内出现的次数>
map<int, int> mp;
int right = 0;
while (right < k) {
mp[nums[right]]++;
++right;
}
vector<int> ans(nums.size() - k + 1, 0);
for (; right < nums.size(); ++right) {
// 利用了map有序的特性
ans[right - k] = (mp.rbegin())->first;
// push新元素
mp[nums[right]]++;
// pop旧元素
auto it = mp.find(nums[right - k]);
if (it->second == 1) {
mp.erase(it);
} else {
--(it->second);
}
}
ans[right - k] = (mp.rbegin())->first;
return ans;
}