C++ 代码
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 1e6 + 10;
int n, k;
int a[N], q[N];
int main()
{
cin >> 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 ++ )
{
while(tt >= hh && q[hh] < i - k + 1) hh ++;
while(tt >= hh && 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 ++ )
{
while(tt >= hh && q[hh] < i - k + 1) hh ++;
while(tt >= hh && a[q[tt]] <= a[i]) tt --;
q[++ tt] = i;
if(i >= k - 1) printf("%d ", a[q[hh]]);
}
return 0;
}
/*
循环队列的模板:
yxc
// hh 表示队头,tt表示队尾的后一个位置
int q[N], hh = 0, tt = 0;
// 向队尾插入一个数
q[tt ++ ] = x;
if (tt == N) tt = 0;
// 从队头弹出一个数
hh ++ ;
if (hh == N) hh = 0;
// 队头的值
q[hh];
// 判断队列是否为空,如果hh != tt,则表示不为空
if (hh != tt)
{
}
您提出的一个非常好的观点。使用 hh != tt 作为判断队列是否为空的条件确实存在一些问题和潜在的边界情况。
在一个循环队列中,当 hh == tt 时,有两种可能的情况:
队列为空
队列已满,并且 hh 和 tt 指向了同一个位置
因此,单纯使用 hh != tt 作为判断队列是否为空的条件是不够的,因为它无法区分上述两种情况。
一个更加健壮和常见的做法是,使用一个额外的变量来记录队列中元素的数量,或者在数组中预留一个空位,从而可以有效地区分队列为空和队列满的情况。
以下是使用额外变量 cnt 记录队列元素数量的示例:
int q[N], hh = 0, tt = 0, cnt = 0;
// 向队尾插入一个数
q[tt++] = x;
if (tt == N) tt = 0;
cnt++;
// 从队头弹出一个数
hh++;
if (hh == N) hh = 0;
cnt--;
// 队头的值
q[hh];
// 判断队列是否为空
if (cnt == 0) {
// 队列为空
}
您也可以预留一个空位,从而可以通过 hh == tt 判断队列为空,通过 (tt + 1) % N == hh 判断队列满的情况:
int q[N], hh = 0, tt = 0;
// 向队尾插入一个数
if ((tt + 1) % N == hh) {
// 队列已满
} else {
q[tt] = x;
tt = (tt + 1) % N;
}
// 从队头弹出一个数
if (hh == tt) {
// 队列为空
} else {
hh = (hh + 1) % N;
}
// 队头的值
q[hh];
// 判断队列是否为空
if (hh != tt) {
// 队列不为空
}
*/