题目
滑动窗口
思路
这是一道滑动窗口的经典题,题目是英文的,但是也很好懂,这里直接将问题抽象出来:
给你一个长度为 n n n 的数组和一个长度为 k k k 的滑动窗口,让你得出窗口从左滑到右的每一步窗口中的最大值和最小值,并打印出来。
题目很直观,但是有一点小麻烦,如果按朴素的方法求解窗口内的最大最小值的话,那复杂度就会很高(我没有测试过按朴素方法能不能过),有可能过不了。所以我们得找一个比较快的方法来得出窗口内的最大最小值,由于窗口是滑动的,则每移动一个位置,就有一个元素被丢弃,一个元素被新加入,所以这道题的核心就是动态维护最大值和最小值。
使用排序树(比如红黑树)就可以很好的解决这个问题,然而红黑树太复杂,不必手搓,使用 S T L STL STL 封装的 s e t set set 即可。并且,窗口内的元素有可能有重复的,所以我们要使用 m u l t i s e t multiset multiset 来存储窗口内的元素,每当窗口移动时, m u l t i s e t multiset multiset 中就相应地增加和减少元素即可。具体见代码。
代码
#include <iostream>
#include <set>
#include <vector>
using namespace std;
int main(void) {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n = 0, k = 0, i = 0;
cin >> n >> k;
vector<int> a(n), mm, mn;
for (i = 0; i < n; i++) {
cin >> a[i];
}
multiset<int> st;
for (i = 0; i < n; i++) {
if (i >= k) {
mn.emplace_back(*st.begin());
mm.emplace_back(*prev(st.end()));
// 注意这里erase不能使用值传递版的重载函数
// 而必须使用迭代器版的重载函数,想想为什么
st.erase(st.find(a[i - k]));
}
st.emplace(a[i]);
}
mn.emplace_back(*st.begin());
mm.emplace_back(*prev(st.end()));
for (auto&& c : mn) {
cout << c << " ";
}
cout << endl;
for (auto&& c : mm) {
cout << c << " ";
}
cout << endl;
return 0;
}