题目:
有一个 a×b 的整数组成的矩阵,现请你从中找出一个 n×n 的正方形区域,使得该区域所有数中的最大值和最小值的差最小。
思路:
对每一行使用单调队列求区间内的最小值和最大值并存储起来,然后对列方向分别求最小值和最大值。最终把每个 n × n n×n n×n的方格的最小值和最大值存储在右下角的位置。然后遍历取答案的最小即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int w[N][N];
int mn[N][N],mx[N][N];
int q[N];
int n,m,k;
void get_min(int a[],int b[],int cnt)
{
int hh=0,tt=-1;
for(int i=1;i<=cnt;i++)
{
if(hh<=tt && q[hh] <= i-k) ++hh;
while(hh<=tt && a[i] <= a[q[tt]]) --tt;
q[++tt] = i;
b[i] = a[q[hh]];
}
}
void get_max(int a[],int b[],int cnt)
{
int hh=0,tt=-1;
for(int i=1;i<=cnt;i++)
{
if(hh<=tt && q[hh] <= i-k) ++hh;
while(hh<=tt && a[i] >= a[q[tt]]) --tt;
q[++tt] = i;
b[i] = a[q[hh]];
}
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&w[i][j]);
//对每一行求
for(int i=1;i<=n;i++)
{
get_max(w[i],mx[i],m);
get_min(w[i],mn[i],m);
}
//在列的方向求最小值和最大值
int res = 1e9;
int a[N],b[N],c[N];
for(int j=k;j<=m;j++)
{
for(int i=1;i<=n;i++) a[i] = mn[i][j];
get_min(a,b,n);
for(int i=1;i<=n;i++) a[i] = mx[i][j];
get_max(a,c,n);
for(int i=k;i<=n;i++)
res = min(res,c[i]-b[i]);
}
printf("%d\n",res);
return 0;
}