核心思想是先暴力想一遍,然后找没有用到的元素并删掉,看剩余元素有无单调性。若有,就用单调栈/单调队列/二分来优化
1.单调栈
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
输入格式
第一行包含整数 N,表示数列长度。
第二行包含 N 个整数,表示整数数列。
输出格式
共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。
数据范围
1≤N≤10^5
1≤数列中元素≤10^9
输入样例:
5 3 4 2 7 5
输出样例:
-1 3 -1 2 2
代码:这里往右遍历,如果遇到一个更小的数,说明之前存的数全部没有用了,所以全部弹出栈。
#include <iostream> using namespace std; const int N = 100010; int n; int stk[N], tt; // i左边的数存入stack,且满足单增栈 int main() { cin >> n; for (int i = 0; i < n; i++) { int x; cin >> x; while (tt && stk[tt] >= x) // 栈非空&&栈顶元素>=x 栈内遇见一个>=x的数就弹出,保证插入x后仍为单增栈 tt--; if (tt) // 非空 cout << stk[tt] << " "; else // 空 cout << -1 << " "; stk[++tt] = x; } return 0; }
2.单调队列
滑动窗口
给定一个大小为 n≤10^6 的数组。
有一个大小为 k 的滑动窗口,它从数组的最左边移动到最右边。
你只能在窗口中看到 k 个数字。
每次滑动窗口向右移动一个位置。
以下是一个例子:
该数组为 [1 3 -1 -3 5 3 6 7],k 为 33。
窗口位置 | 最小值 | 最大值 |
[1 3 -1] -3 5 3 6 7 | -1 | 3 |
1 [3 -1 -3] 5 3 6 7 | -3 | 3 |
1 3 [-1 -3 5] 3 6 7 | -3 | 5 |
1 3 -1 [-3 5 3] 6 7 | -3 | 5 |
1 3 -1 -3 [5 3 6] 7 | 3 | 6 |
1 3 -1 -3 5 [3 6 7] | 3 | 7 |
你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。
输入格式
输入包含两行。
第一行包含两个整数 n 和 k,分别代表数组长度和滑动窗口的长度。
第二行有 n 个整数,代表数组的具体数值。
同行数据之间用空格隔开。
输出格式
输出包含两个。
第一行输出,从左至右,每个位置滑动窗口中的最小值。
第二行输出,从左至右,每个位置滑动窗口中的最大值。
输入样例:
8 3 1 3 -1 -3 5 3 6 7
输出样例:
-1 -3 -3 -3 3 3 3 3 5 5 6 7
代码:无用元素1:不在窗口的元素;无用元素2:在窗口中最小值>要进来的元素,之前的最小值删去,保留新的最小值。
#include <iostream> using namespace std; const int N = 1000010; int n, k; int a[N], q[N]; // q[]存元素下标 int main() { scanf("%d %d", &n, &k); int hh = 0, tt = -1; for (int i = 0; i < n; i++) { scanf("%d", &a[i]); } for (int i = 0; i < n; i++) // 输出最小元素 { // 判断队头是否已经溢出窗口 if (hh <= tt && i - k + 1 > q[hh]) // 不用while因为每次窗口只滑动一格 { hh++; } while (hh <= tt && a[q[tt]] > a[i]) { // 如果要进来的元素<队尾元素 tt--; } q[++tt] = i; // 这里的位置不能变 if (i >= k - 1) { printf("%d ", a[q[hh]]); } } cout << endl; hh = 0, tt = -1;//记得要重置!!!! for (int i = 0; i < n; i++) // 输出最大元素 { // 判断队头是否已经溢出窗口 if (hh <= tt && i - k + 1 > q[hh]) // 不用while因为每次窗口只滑动一格 { hh++; } while (hh <= tt && a[q[tt]] < a[i]) { // 如果要进来的元素>队尾元素 tt--; } q[++tt] = i; // 这里的位置不能变 if (i >= k - 1) { printf("%d ", a[q[hh]]); } } return 0; }