Description
有一个长为 n 的序列 a,以及一个大小为 k 的窗口。现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值。
例如,对于序列 [1,3,−1,−3,5,3,6,7][1,3,−1,−3,5,3,6,7] 以及 k=3,有如下过程:
窗口位置最小值最大值
Input
输入一共有两行,第一行有两个正整数 n,k。
第二行 n 个整数,表示序列 a
Output
输出共两行,第一行为每次窗口滑动的最小值
第二行为每次窗口滑动的最大值
Sample 1
Inputcopy | Outputcopy |
---|---|
8 3 1 3 -1 -3 5 3 6 7 | -1 -3 -3 -3 3 3 3 3 5 5 6 7 |
Hint
【数据范围】
对于 50%50% 的数据,1≤n≤10^5;
对于 100%100% 的数据,1≤k≤n≤10^6,ai∈[−2^31,2^31)。
#include<iostream> // 引入标准输入输出库
using namespace std; // 使用标准命名空间
const int N=1000010; // 定义常量 N,表示数组的最大长度
int a[N],q[N]; // 定义两个全局数组 a 和 q
int main() { // 程序入口函数
int n,k; // 定义变量 n 和 k,分别表示数组大小和滑动窗口大小
scanf("%d%d",&n,&k); // 从标准输入读取 n 和 k 的值
for(int i=0; i<n; i++) { // 循环读取数组 a 的每个元素
scanf("%d",&a[i]);
}
int hh=0,tt=-1; // 初始化队列的头部和尾部指针
for(int i=0; i<n; i++) { // 第一个循环,寻找最小值
if(hh<=tt && i-q[hh]>k-1) { // 如果队列头部的元素已经不在窗口内,出队
hh++;
}
while(hh<=tt&&a[q[tt]]>=a[i]) // while 循环,确保队列的单调性
tt--; // 如果队列尾部的元素大于等于新元素,出队
q[++tt]=i; // 将新元素的下标加入队列尾部
if(i>=k-1) // 如果当前位置 i 大于等于 k-1,输出队列头部的元素
printf("%d ",a[q[hh]]);
}
puts(""); // 输出一个换行符
hh=0,tt=-1; // 重置队列的头部和尾部指针
for(int i=0; i<n; i++) { // 第二个循环,寻找最大值
if(hh<=tt && i-q[hh]>k-1) { // 如果队列头部的元素已经不在窗口内,出队
hh++;
}
while(hh<=tt&&a[q[tt]]<=a[i]) // while 循环,确保队列的单调性
tt--; // 如果队列尾部的元素小于等于新元素,出队
q[++tt]=i; // 将新元素的下标加入队列尾部
if(i>=k-1) // 如果当前位置 i 大于等于 k-1,输出队列头部的元素
printf("%d ",a[q[hh]]);
}
puts(""); // 输出一个换行符
}
这段代码是用来实现滑动窗口中的最大值和最小值的问题。下面是代码的解析思路:
- 引入标准输入输出库,并使用标准命名空间。
- 定义常量 N,表示数组的最大长度。
- 定义两个全局数组 a 和 q,其中 a 用来存储数组的元素,q 用来存储滑动窗口中的下标。
- 程序入口函数 main()。
- 从标准输入读取 n 和 k 的值,分别表示数组大小和滑动窗口大小。
- 使用循环读取数组 a 的每个元素,并存储到 a 数组中。
- 初始化队列的头部指针 hh 和尾部指针 tt,其中 hh = 0,tt = -1。
- 第一个循环用来寻找最小值,其中 i 表示当前遍历的位置。
- 如果队列头部的元素已经不在窗口内,即 i - q[hh] > k-1,队列头部元素出队。
- 使用 while 循环,确保队列的单调性,即队列中的元素按照递增顺序排列。
- 如果队列尾部的元素大于等于新元素 a[i],则队尾元素出队。
- 将新元素的下标 i 加入队列尾部。
- 如果当前位置 i 大于等于 k-1,输出队列头部的元素 a[q[hh]],即当前窗口的最小值。
- 第一个循环结束后,输出一个换行符。
- 重置队列的头部和尾部指针,即 hh = 0,tt = -1。
- 第二个循环用来寻找最大值,逻辑与第一个循环类似。
- 最后输出一个换行符。