核心思想是先暴力想一遍,然后找没有用到的元素并删掉,看剩余元素有无单调性。若有,就用单调栈/单调队列/二分来优化
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;
}