因为markdown语法不完成就不写题目描述了,自己对着题目看
思路
- 首先判断窗口位置是否合理
- 根据所给的窗口大小和队头元素所对应的下标进行判断
- i - k + 1 代表当前窗口的左端的位置
- q[ hh ] 代表队头元素在原数组所对应的下标
- if (i - k + 1 > q[ hh ]) hh ++ 说明队头不在窗口之内,那就需要移动队头来调整位置
- 根据需要的单调性进行剔除元素
- 当需要输出窗口最小值时
- num[i] 代表当前元素
- num[ q[ tt ]] 代表队尾元素
- 如果队尾元素大于新元素,则删除队尾元素,俗话来讲就是 只要新元素在 那么比新元素大的元素就永无出头之日
- if(num[i) <= num[ q[ tt ]]) tt –
- 当需要输出窗口最大值时
- num[i] 代表当前元素
- num[ q[ tt ]] 代表队尾元素
- 如果队尾元素小于新元素,则删除队尾元素,俗话来讲就是 只要新元素在 那么比新元素小的元素就永无出头之日
- if(num[i] >= num[ q[ tt ]) tt –
- 当需要输出窗口最小值时
- 存入新元素的下标
- q[ ++ tt ] = i 存入的是原数组的下标
- 输出元素
- printf(“%d “,num[ q[ hh ]]) 输出队列中队头所对应的元素,因为留下的元素具有单调性,
队头那个元素肯定是所需元素(不信画图)
- printf(“%d “,num[ q[ hh ]]) 输出队列中队头所对应的元素,因为留下的元素具有单调性,
代码如下
#include <iostream>
using namespace std;
const int N = 1000010;
int q[N],num[N];
int main(){
int n,k;
cin >> n >> k;
for(int i = 0;i < n;i++) scanf("%d",&num[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 && num[i] <= num[q[tt]]) tt --;
q[++ tt] = i;
if(i + 1 >= k) printf("%d ",num[q[hh]]);// 这里比较用 >= 只要是一个完整的窗口就可以输出
}
printf("\n");
//再输出窗口的最大值
hh = 0,tt = -1;
for(int i = 0;i < n;i ++){
if(hh <= tt && i - k + 1 > q[hh]) hh ++;//i - k + 1 是当前窗口的左端位置,
//如果左端位置大于了队头,就调整队头
while(hh <= tt && num[i] >= num[q[tt]]) tt --;
q[++ tt] = i;
if(i + 1 >= k) printf("%d ",num[q[hh]]);
}
printf("\n");
return 0;
}
好棒
确实