【数据结构】单调队列专题(滑动窗口问题)
一维滑动窗口
154. 滑动窗口
下标从0开始,数组模拟队列
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int a[N], q[N];
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
int hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;
while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
}
puts("");
hh = 0, tt = -1;
for (int i = 0; i < n; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;
while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k - 1) printf("%d ", a[q[hh]]);
}
return 0;
}
作者:NFYD
链接:https://www.acwing.com/activity/content/code/content/1161854/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
下标从0开始,STL队列
#include <iostream>
#include <deque>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int a[N];
int main()
{
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i ++ ) scanf("%d", &a[i]);
deque<int> q;
for (int i = 0; i < n; i ++ )
{
if (q.size() && i - (k - 1) > q.front()) q.pop_front();
while (q.size() && a[q.back()] >= a[i]) q.pop_back();
q.push_back(i);
if (i >= k - 1) printf("%d ", a[q.front()]); // 注:输出的是队头元素
}
printf("\n");
q = deque<int>();
for (int i = 0; i < n; i ++ )
{
if (q.size() && i - (k - 1) > q.front()) q.pop_front();
while (q.size() && a[q.back()] <= a[i]) q.pop_back();
q.push_back(i);
if (i >= k - 1) printf("%d ", a[q.front()]); // 注:输出的是队头元素
}
return 0;
}
作者:NFYD
链接:https://www.acwing.com/activity/content/code/content/1161854/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
下标从1开始,数组模拟队列
#include <iostream>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int q[N], a[N];
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
int hh = 0, tt = -1;
for (int i = 1; i <= n; i ++ )
{
if (hh <= tt && i - k >= q[hh]) hh ++ ; // 也可写成i - k + 1 > q[hh]
while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k) printf("%d ", a[q[hh]]);
}
puts("");
hh = 0, tt = -1;
for (int i = 1; i <= n; i ++ )
{
if (hh <= tt && i - k >= q[hh]) hh ++ ; // 也可写成i - k + 1 > q[hh]
while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k) printf("%d ", a[q[hh]]);
}
return 0;
}
作者:NFYD
链接:https://www.acwing.com/activity/content/code/content/1161854/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
二维滑动窗口
1091. 理想的正方形
#include <iostream>
using namespace std;
const int N = 1010;
int n, m, k;
int w[N][N], row_max[N][N], row_min[N][N];
int q[N];
void get_max(int a[], int b[], int tot)
{
int hh = 0, tt = -1;
for (int i = 0; i < tot; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;
while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k - 1) b[i] = a[q[hh]];
}
}
void get_min(int a[], int b[], int tot)
{
int hh = 0, tt = -1;
for (int i = 0; i < tot; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;
while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k - 1) b[i] = a[q[hh]];
}
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
scanf("%d", &w[i][j]);
for (int i = 0; i < n; i ++ ) // 枚举每一行的最值
{
get_max(w[i], row_max[i], m);
get_min(w[i], row_min[i], m);
}
int a[N], b[N], c[N], res = 1e9;
for (int i = k - 1; i < m; i ++ )
{
for (int j = 0; j < n; j ++ ) a[j] = row_max[j][i];
get_max(a, b, n);
for (int j = 0; j < n; j ++ ) a[j] = row_min[j][i];
get_min(a, c, n);
for (int j = k - 1; j < n; j ++ )
res = min(res, b[j] - c[j]);
}
printf("%d\n", res);
return 0;
}
作者:NFYD
链接:https://www.acwing.com/activity/content/code/content/1600528/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
4964. 子矩阵
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1010, mod = 998244353;
int n, m, A, B;
int w[N][N];
int row_min[N][N], row_max[N][N];
int q[N];
void get_max(int a[], int b[], int tot, int k) // k为窗口长度,tot为区间总长度
{
int hh = 0, tt = -1;
for (int i = 0; i < tot; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;
while (hh <= tt && a[q[tt]] <= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k - 1) b[i] = a[q[hh]];
}
}
void get_min(int a[], int b[], int tot, int k) // k为窗口长度,tot为区间总长度
{
int hh = 0, tt = -1;
for (int i = 0; i < tot; i ++ )
{
if (hh <= tt && i - k + 1 > q[hh]) hh ++ ;
while (hh <= tt && a[q[tt]] >= a[i]) tt -- ;
q[++ tt] = i;
if (i >= k - 1) b[i] = a[q[hh]];
}
}
int main()
{
scanf("%d%d%d%d", &n, &m, &A, &B);
for (int i = 0; i < n; i ++ )
for (int j = 0; j < m; j ++ )
scanf("%d", &w[i][j]);
for (int i = 0; i < n; i ++ )
{
get_max(w[i], row_max[i], m, B);
get_min(w[i], row_min[i], m, B);
}
int res = 0;
int a[N], b[N], c[N];
for (int i = B - 1; i < m; i ++ ) // 枚举每一列
{
for (int j = 0; j < n; j ++ ) a[j] = row_max[j][i];
get_max(a, b, n, A);
for (int j = 0; j < n; j ++ ) a[j] = row_min[j][i];
get_min(a, c, n, A);
for (int j = A - 1; j < n; j ++ )
res = (res + (LL)b[j] * c[j]) % mod;
}
printf("%d\n", res);
return 0;
}
作者:NFYD
链接:https://www.acwing.com/activity/content/code/content/6402744/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。