题目描述
有一个长为 ( n ) 的序列 ( a ),以及一个大小为 ( k ) 的窗口。现在这个窗口从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。例如:
数组是 ([1, 3, -1, -3, 5, 3, 6, 7]), ( k = 3 )。
输入格式
输入一共有两行:
第一行有两个正整数 ( n ) 和 ( k )。
第二行有 ( n ) 个整数,表示序列 ( a )。
输出格式
输出共两行:
第一行为每次窗口滑动的最小值。
第二行为每次窗口滑动的最大值。
样例
输入数据 1
8 3
1 3 -1 -3 5 3 6 7
输出数据 1
-1 -3 -3 -3 3 3
3 3 5 5 6 7
提示
数据范围:
- 对于 50% 的数据,( 1 \leq n \leq 10^5 )
- 对于 100% 的数据,( 1 \leq k \leq n \leq 10^6 ),( a_i \in [-2^{31}, 2^{31}) )
参考代码:双端队列实现
#include <bits/stdc++.h>using namespace std;constexpr int N = 1e6 + 7;int a[N], n, k;int main() {cin >> n >> k;for (int i = 0; i < n; i++) cin >> a[i];// 存的是下标// 我们的dq里面一定是单调// 你要么活得比我长// 要么能力比我强deque<int> dq;for (int i = 0; i < n; i++) {// 当前队首的这个点还存活不 --- 窗口长度k// 比如我当前位置是i,窗口长度是3// 可以存在的点是i, i - 1, i - 2if (!dq.empty() && i - k + 1 > dq.front()) {// 比如我现在的i = 6,k = 3 --- 4 5 6三个位置的数// 但是你的dq.frond() = 3,你队首是位置为3的元素// 已经过了你的时代 --- 你该下位了dq.pop_front();}// 我a[i]要把我前面能力没我强,活的没我久的全部干掉// 队列里如果活得没有a[i]久,能力没有a[i]强,a[i]在的一天他们就永无出头之日while (!dq.empty() && a[i] <= a[dq.back()]) dq.pop_back();dq.push_back(i);// 可以输出当前的最小值了 --- 窗口长度至少得达到k才可以开始输出if (i >= k - 1) cout << a[dq.front()] << " ";}cout << "\n";dq.clear();for (int i = 0; i < n; i++) {// 当前队首的这个点还存活不 --- 窗口长度k// 比如我当前位置是i,窗口长度是3// 可以存在的点是i, i - 1, i - 2if (!dq.empty() && i - k + 1 > dq.front()) {// 比如我现在的i = 6,k = 3 --- 4 5 6三个位置的数// 但是你的dq.frond() = 3,你队首是位置为3的元素// 已经过了你的时代 --- 你该下位了dq.pop_front();}// 我a[i]要把我前面能力没我强,活的没我久的全部干掉// 队列里如果活得没有a[i]久,能力没有a[i]强,a[i]在的一天他们就永无出头之日while (!dq.empty() && a[i] >= a[dq.back()]) dq.pop_back();dq.push_back(i);// 可以输出当前的最小值了 --- 窗口长度至少得达到k才可以开始输出if (i >= k - 1) cout << a[dq.front()] << " ";}cout << "\n";return 0;
}
参考代码:手写单调队列
#include <bits/stdc++.h>using namespace std;constexpr int N = 1e6 + 7;int a[N], dq[N];int n, k, head = 0, tail = -1;bool isNotEmpty() { return head <= tail; }int top() { return dq[head]; }void pop_front() { head += 1; }int back() { return dq[tail]; }void pop_back() { tail -= 1; }void push(int x) { dq[++tail] = x; }int main() {cin >> n >> k;for (int i = 0; i < n; i++) cin >> a[i];for (int i = 0; i < n; i++) {if (isNotEmpty() && i - k + 1 > top()) pop_front();while (isNotEmpty() && a[back()] >= a[i]) pop_back();push(i);if (i >= k - 1) cout << a[top()] << " ";}cout << "\n";head = 0, tail = -1;for (int i = 0; i < n; i++) {if (isNotEmpty() && i - k + 1 > top()) pop_front();while (isNotEmpty() && a[back()] <= a[i]) pop_back();push(i);if (i >= k - 1) cout << a[top()] << " ";}cout << "\n";return 0;
}